Introduction

Two weeks ago, you spent some time learning about ways to measure the distribution of the population by race and ethnicity. This lab builds upon that past knowledge, primarily by helping you to visualize and analyze these distributions spatially.

Description and Goals

In this lab, we will use American Community Survey data to perform some exploratory data visualization for the Chicago Metropolitan Area, focusing on describing residential segregation based upon race and income. Our goals for this lab are as follows:

  • Continue to gain experience with tidycensus and ggplot
  • Learn some additional qualities of simple feature geometries, which allows R to manipulate spatial data
  • Gain more experience with geom_sf() and mapping simple feature geometries
  • Apply several measures of spatial segregation to analyze regional patterns

By the end of this lab, you will implement a data pipeline to programmatically download, map, and describe elements of residential segregation for a city and its region.

Set Up Workspace

Let’s go ahead and programmatically create a few directories to help us keep our workspace organized. You’ll recall that we learned how to use dir.create() in the past to insert new directories into our “home” directory which is set based upon where our project .Rmd file is located.In this case, we’ll create the typical folders we work with to keep our labs organized - data, documentation, output, and scripts.

```r
dir.create(\data\)

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiJ2RhdGEnIGFscmVhZHkgZXhpc3RzXG4ifQ== -->

‘data’ already exists




<!-- rnb-output-end -->

<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuZGlyLmNyZWF0ZShcXGRvY3VtZW50YXRpb25cXClcbmBgYFxuYGBgIn0= -->

```r
```r
dir.create(\documentation\)

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiJ2RvY3VtZW50YXRpb24nIGFscmVhZHkgZXhpc3RzXG4ifQ== -->

‘documentation’ already exists




<!-- rnb-output-end -->

<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuZGlyLmNyZWF0ZShcXG91dHB1dFxcKVxuYGBgXG5gYGAifQ== -->

```r
```r
dir.create(\output\)

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiJ291dHB1dCcgYWxyZWFkeSBleGlzdHNcbiJ9 -->

‘output’ already exists




<!-- rnb-output-end -->

<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuZGlyLmNyZWF0ZShcXHNjcmlwdHNcXClcbmBgYFxuYGBgIn0= -->

```r
```r
dir.create(\scripts\)

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiJ3NjcmlwdHMnIGFscmVhZHkgZXhpc3RzXG4ifQ== -->

‘scripts’ already exists




<!-- rnb-output-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


## Load Required Packages
Let's start by loading the `tidyverse` and `tidycensus` packages. You can add other packages here as we need them so that they load at the beginning of our notebook.


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxubGlicmFyeSh0aWR5dmVyc2UpXG5gYGAifQ== -->

```r
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ---------------------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.3     v purrr   0.3.4
v tibble  3.0.5     v dplyr   1.0.3
v tidyr   1.1.2     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.1
-- Conflicts ------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(tidycensus)
census_api_key("f6d3f308f00a0ffda3aa19e86807e0ea5960d86e", install = TRUE, overwrite=TRUE)
Your original .Renviron will be backed up and stored in your R HOME directory if needed.
Your API key has been stored in your .Renviron and can be accessed by Sys.getenv("CENSUS_API_KEY"). 
To use now, restart R or run `readRenviron("~/.Renviron")`
[1] "f6d3f308f00a0ffda3aa19e86807e0ea5960d86e"

Download Census Data

Download ACS Data

Now let’s go ahead and download some census data which we’ll use to calculate segregation measures with. For this lab, we’ll download the data at the census tract level for all tracts in Illinois (later on, we’ll pull out pertinent counties in the Chicago metropolitan statistical area). Let’s calculate the following measures:

ACS Table Variables Label Description
B01001 B01001_001E Pop Total Population
B02001 B02001_002E White Count of White Population
B02001 B02001_003E Black Count of Black Population
B02001 B02001_004E AIAN Count of American Indian and Alaskan Native Population
B02001 B02001_005E Asian Count of Asian Population
B02001 B02001_001E, B02001_002E Nonwhite Count of Nonwhite Population
B03001 B03001_003E Latino Count of Latino Population
B19013 B19013_001E MHHI Median Household Income

I am going to do you a favor - I have written a script that will download these variables for you. In order for it to work, you will need to supply the script with some variables, namely your census API key, the download year, the geographic summary level you wish to download, the state, and the ACS survey product you wish to download. Let’s download 2019 5-year American Community Survey data.

  • api_key: Your Census API Key
  • DL_Year: The end year for the data you wish to download
  • survey: The name of the survey you wish to download (this coud be “acs1”, “acs3”, or “acs5”)
  • geo: The geographic summary level you wish to download (following tidycensus nomenclature)
  • state: The name(s) of the state(s) you wish to download data for.
# Your Work Here
api_key<-"f6d3f308f00a0ffda3aa19e86807e0ea5960d86e"
DL_Year<-2019
survey <- "acs5"
geo<-"tract"
state<-c("IL")

If you look in the lab folder, there is a script called “1_Get_ACS.R”

Take a look at how the get_acs() call is set up within the script. What’s going on here?

Your Description

We can ask R to run this entire script for us using the source() command. Make sure your variabes are correctly set up above before running:

source("1_Get_ACS.R")
To install your API key for use in future sessions, run this function with `install = TRUE`.
Getting data from the 2015-2019 5-year ACS
Using FIPS code '17' for state 'IL'
Getting data from the 2015-2019 5-year ACS
Using FIPS code '17' for state 'IL'
Getting data from the 2015-2019 5-year ACS
Using FIPS code '17' for state 'IL'
Getting data from the 2015-2019 5-year ACS
Using FIPS code '17' for state 'IL'

R is running all of the code contained in that script without us having to open it. It starts at the beginning and runs until it reaches the end of the script. This can be useful for creating code sub-components that you can run from within other scripts or notebooks.

You now have a dataset called acs_data containing 3,123 observations of 15 variables. These variables include the population (Pop), Population by race and ethnicity, and the median household income (MHHI) for each census tract. I’ve also calculated for you the percent of the population by race and ethnicity (you should check the script to see how this was done). Ok - we have our ACS data.

Download Geographic Data

Next, let’s also download spatial data associated with tract geographies.

The tigris package is designed to download data directly from the census API. Unlike the tidycensus package, it does not require an API key. tigris can download geographies as shapefiles (a format commonly used by commercial GIS programs like ArcGIS), but even more conveniently, it can download these data in a format called simple features.

As you should recall from our last session, Simple Features (the sf package) store geographic attributes as rows in a table, with a special additional row called geometry which stores the coordinates associated with the geography. These coordinates are stored as a list which R can then recall and plot out. You can read more about how simple features are organized here.

Let’s download census tracts for Illinois and take a look. Tigris can download a range of geography types. We can use the tracts() function to download tracts. We specify a state and also specify that we want tigris to download the spatial information in simple feature format class="sf".

Load both the tigris and sf package and download tracts for Illinois into an object called il_trt.

library(sf)
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(tigris)
To enable 
caching of data, set `options(tigris_use_cache = TRUE)` in your R script or .Rprofile.
il_trt<-tracts(state="IL", class="sf")
Using FIPS code '17' for state 'IL'

  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |                                                                      |   1%
  |                                                                            
  |=                                                                     |   1%
  |                                                                            
  |=                                                                     |   2%
  |                                                                            
  |==                                                                    |   2%
  |                                                                            
  |==                                                                    |   3%
  |                                                                            
  |===                                                                   |   4%
  |                                                                            
  |===                                                                   |   5%
  |                                                                            
  |====                                                                  |   5%
  |                                                                            
  |====                                                                  |   6%
  |                                                                            
  |=====                                                                 |   7%
  |                                                                            
  |=====                                                                 |   8%
  |                                                                            
  |======                                                                |   8%
  |                                                                            
  |======                                                                |   9%
  |                                                                            
  |=======                                                               |   9%
  |                                                                            
  |=======                                                               |  10%
  |                                                                            
  |========                                                              |  11%
  |                                                                            
  |========                                                              |  12%
  |                                                                            
  |=========                                                             |  13%
  |                                                                            
  |==========                                                            |  14%
  |                                                                            
  |==========                                                            |  15%
  |                                                                            
  |===========                                                           |  15%
  |                                                                            
  |===========                                                           |  16%
  |                                                                            
  |============                                                          |  16%
  |                                                                            
  |============                                                          |  17%
  |                                                                            
  |============                                                          |  18%
  |                                                                            
  |=============                                                         |  19%
  |                                                                            
  |==============                                                        |  19%
  |                                                                            
  |==============                                                        |  20%
  |                                                                            
  |==============                                                        |  21%
  |                                                                            
  |===============                                                       |  21%
  |                                                                            
  |===============                                                       |  22%
  |                                                                            
  |================                                                      |  22%
  |                                                                            
  |================                                                      |  23%
  |                                                                            
  |=================                                                     |  24%
  |                                                                            
  |=================                                                     |  25%
  |                                                                            
  |==================                                                    |  25%
  |                                                                            
  |==================                                                    |  26%
  |                                                                            
  |===================                                                   |  27%
  |                                                                            
  |===================                                                   |  28%
  |                                                                            
  |====================                                                  |  28%
  |                                                                            
  |====================                                                  |  29%
  |                                                                            
  |=====================                                                 |  30%
  |                                                                            
  |=====================                                                 |  31%
  |                                                                            
  |======================                                                |  31%
  |                                                                            
  |======================                                                |  32%
  |                                                                            
  |=======================                                               |  32%
  |                                                                            
  |=======================                                               |  33%
  |                                                                            
  |========================                                              |  34%
  |                                                                            
  |========================                                              |  35%
  |                                                                            
  |=========================                                             |  35%
  |                                                                            
  |=========================                                             |  36%
  |                                                                            
  |==========================                                            |  37%
  |                                                                            
  |==========================                                            |  38%
  |                                                                            
  |===========================                                           |  38%
  |                                                                            
  |===========================                                           |  39%
  |                                                                            
  |============================                                          |  39%
  |                                                                            
  |============================                                          |  40%
  |                                                                            
  |============================                                          |  41%
  |                                                                            
  |=============================                                         |  41%
  |                                                                            
  |=============================                                         |  42%
  |                                                                            
  |==============================                                        |  42%
  |                                                                            
  |==============================                                        |  43%
  |                                                                            
  |===============================                                       |  44%
  |                                                                            
  |===============================                                       |  45%
  |                                                                            
  |================================                                      |  45%
  |                                                                            
  |================================                                      |  46%
  |                                                                            
  |=================================                                     |  46%
  |                                                                            
  |=================================                                     |  47%
  |                                                                            
  |=================================                                     |  48%
  |                                                                            
  |==================================                                    |  48%
  |                                                                            
  |==================================                                    |  49%
  |                                                                            
  |===================================                                   |  49%
  |                                                                            
  |===================================                                   |  50%
  |                                                                            
  |===================================                                   |  51%
  |                                                                            
  |====================================                                  |  51%
  |                                                                            
  |====================================                                  |  52%
  |                                                                            
  |=====================================                                 |  52%
  |                                                                            
  |=====================================                                 |  53%
  |                                                                            
  |=====================================                                 |  54%
  |                                                                            
  |======================================                                |  54%
  |                                                                            
  |======================================                                |  55%
  |                                                                            
  |=======================================                               |  55%
  |                                                                            
  |=======================================                               |  56%
  |                                                                            
  |========================================                              |  57%
  |                                                                            
  |========================================                              |  58%
  |                                                                            
  |=========================================                             |  58%
  |                                                                            
  |=========================================                             |  59%
  |                                                                            
  |==========================================                            |  59%
  |                                                                            
  |==========================================                            |  60%
  |                                                                            
  |==========================================                            |  61%
  |                                                                            
  |===========================================                           |  61%
  |                                                                            
  |===========================================                           |  62%
  |                                                                            
  |============================================                          |  62%
  |                                                                            
  |============================================                          |  63%
  |                                                                            
  |=============================================                         |  64%
  |                                                                            
  |=============================================                         |  65%
  |                                                                            
  |==============================================                        |  65%
  |                                                                            
  |==============================================                        |  66%
  |                                                                            
  |===============================================                       |  67%
  |                                                                            
  |===============================================                       |  68%
  |                                                                            
  |================================================                      |  68%
  |                                                                            
  |================================================                      |  69%
  |                                                                            
  |=================================================                     |  70%
  |                                                                            
  |=================================================                     |  71%
  |                                                                            
  |==================================================                    |  71%
  |                                                                            
  |==================================================                    |  72%
  |                                                                            
  |===================================================                   |  72%
  |                                                                            
  |===================================================                   |  73%
  |                                                                            
  |====================================================                  |  74%
  |                                                                            
  |====================================================                  |  75%
  |                                                                            
  |=====================================================                 |  75%
  |                                                                            
  |=====================================================                 |  76%
  |                                                                            
  |======================================================                |  77%
  |                                                                            
  |======================================================                |  78%
  |                                                                            
  |=======================================================               |  78%
  |                                                                            
  |=======================================================               |  79%
  |                                                                            
  |========================================================              |  79%
  |                                                                            
  |========================================================              |  80%
  |                                                                            
  |========================================================              |  81%
  |                                                                            
  |=========================================================             |  81%
  |                                                                            
  |=========================================================             |  82%
  |                                                                            
  |==========================================================            |  82%
  |                                                                            
  |==========================================================            |  83%
  |                                                                            
  |==========================================================            |  84%
  |                                                                            
  |===========================================================           |  84%
  |                                                                            
  |===========================================================           |  85%
  |                                                                            
  |============================================================          |  85%
  |                                                                            
  |============================================================          |  86%
  |                                                                            
  |=============================================================         |  87%
  |                                                                            
  |=============================================================         |  88%
  |                                                                            
  |==============================================================        |  88%
  |                                                                            
  |==============================================================        |  89%
  |                                                                            
  |===============================================================       |  90%
  |                                                                            
  |===============================================================       |  91%
  |                                                                            
  |================================================================      |  91%
  |                                                                            
  |================================================================      |  92%
  |                                                                            
  |=================================================================     |  92%
  |                                                                            
  |=================================================================     |  93%
  |                                                                            
  |=================================================================     |  94%
  |                                                                            
  |==================================================================    |  94%
  |                                                                            
  |==================================================================    |  95%
  |                                                                            
  |===================================================================   |  95%
  |                                                                            
  |===================================================================   |  96%
  |                                                                            
  |====================================================================  |  97%
  |                                                                            
  |====================================================================  |  98%
  |                                                                            
  |===================================================================== |  98%
  |                                                                            
  |===================================================================== |  99%
  |                                                                            
  |======================================================================|  99%
  |                                                                            
  |======================================================================| 100%

Take a look at the tract data - each row is a census tract. There are multiple columns describing each tract. The geometry column contains coordinates.

Confirm that you got what you were expecting by plotting these data. Remember that in ggplot, you can use geom_sf() to plot. It will take a moment to plot, as it is rendering lots of detail for each census tract in Illinois:

# Your Code Here
ggplot() + geom_sf(data=il_trt)

This plot looks roughly like the state of Illinois - good enough to feel comfortable with moving forward.

Go ahead and join the ACS data contained in acs_data data to the tract data contained in il_trt. The common field between the two is GEOID.

# Your Code Here
il_trt <- left_join(il_trt, acs_data, by = "GEOID")

Re-introducing geom_sf()

We have not programmatically downloaded geographic and tract attribute data and joined them together. Let’s venture into using R as a way to visualize spatial data.

Last week, you began exploring the visualization features of the ggplot2 package. Let’s continue to build on this by plotting our data containing simple feature geometries. We’re going to focus specifically on understanding dimensions of segregation for census tracts in the Chicago metropolitan area.

Let’s go ahead and select a subset of these data - the census tracts for the counties that make up the Illinois portion of the Chicago Metropolitan Area. For your convenience, here’s the names of those counties and their associated county FIPS codes:

County FIPS
Cook 031
DeKalb 037
DuPage 043
Grundy 063
Kane 089
Kendall 093
Lake 097
McHenry 111
Will 197

Create a new object called “chi” which contains the records from il_trt for the subset of Illinois counties that are in the Chicago metropolitan area. After this, go ahead and create a map of these Chicago metropolitan tracts.

Okay - now we’re getting somewhere - we can see more of the definition of the tracts. Something should give you pause, however. There are two gigantic tracts which cover portions of Lake Michigan associated with Cook and Lake Counties (For those not familiar with Chicago, Cook County is the county in which Chicago is located and Lake County is just north of it). These two tracts contain no population (they’re all water, after all) and we can remove them.

Look through the il_trt dataset and identify the two tracts for which ALAND (land area) is 0. Filter these out of chi, and then re-plot.

# Your Code Here
chi <- chi %>% filter(!GEOID %in% c("17031990000","17097990000"))
ggplot()+geom_sf(data = chi)

Mapping Race

Okay - we’ve got the geographic component of our data sorted out. Now let’s try visualizing some of the attributes of the data. We’ve already mapped the tracts for which we’re interested in seeing race information for. To visualize an attribute of the dataset, we need to add an aesthetic mapping using aes(). In this case, we want to specify that the fill color for each of our census tracts comes from a particular variable (column) from the il_trt data table. Let’s start by visualizing the PWhite (percent white) data:

ggplot()+geom_sf(data=chi, aes(fill = PWhite))

Okay - we have a map that now also includes a legend for our continuous variable (percentage white). We also have a few tracts that are grayed out - they have no population (notice that one of these is O’Hare airport).

One challenge here is that at this scale, the tract boundaries (gray lines) obscure some of the census tract data. We could set the line color (census tract boundary) to be the same as the data for its respective tract using the colour aesthetic mapping:

ggplot()+geom_sf(data=chi, aes(fill = PWhite, colour = PWhite))

This certainly allows us to see the tract data clearly.

It might be useful to have some boundaries to help us here. County boundaries, for instance might be useful. We could download the county data, or we could simply generate it from the tract data which we already have.

One special feature of simple features (sf) objects is that we can use group_by() and summarise() as we would on our data table, and it will also re-calculate and aggregate geometries in our maps. In this case, we can use our census tracts (which are hierarchical) to generate our county-level data and geographies. While we’re at it, let’s also summarize counts for population, race, and ethnicity:

co<-chi %>% group_by(COUNTYFP) %>% summarise(
  Pop_co = sum(Pop),
  White_co = sum(White),
  Black_co = sum(Black),
  AIAN_co = sum(AIAN),
  Asian_co = sum(Asian),
  Latino_co = sum(Latino),
  Nonwhite_co = sum(Nonwhite)
  )
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
co
Simple feature collection with 9 features and 8 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

Now go ahead and plot the county-level data (no fill yet):

# Your Code Here
ggplot() + geom_sf(data = co)

We created county boundaries from our census tracts.

We can now layer the counties in with our tract level data. We need to tell ggplot not to include fill for the county-level data so that we can see the tracts below them:

ggplot()+
  geom_sf(data=chi, aes(fill = PWhite, colour = PWhite))+
  geom_sf(data=co, fill=NA)

See how plotting county boundaries over the tract-level data helps to give us a point of reference for our map?

While we’re at it, it might be useful for us to think about other ways to represent these data. The map is helpful, but we may also want to look at univariate characteristics. Building upon your knowledge from prior weeks, make a histogram of the percentage white population for the Chicago Metro area using geom_histogram():

# Your Code Here
ggplot() + geom_histogram(data=chi, aes(x=PWhite))

Take a look at the distribution of tracts - how would you characterize or describe this?

We learned briefly about faceting in our introductory data visualization lab. Let’s try that again here. Use facets to split our data into smaller multiples that can be plotted separately. Let’s add a facet using facet_wrap() based upon the county (facet_wrap~COUNTYFP)):

# Your Code Here
ggplot() + 
geom_histogram(data=chi, aes(x=PWhite)) +
facet_wrap(~COUNTYFP)

How would you describe this visualization in plain text? How might we improve this or make it more legible? County 031, presumably Cook, has the most tracts by far and most consists of homogenously black and majority white tracts. The other counties have much fewer tracts, with a clear white majority in most of them. Having more levels on the y axis, a better color, and axis labels (percentage and tract count), along with a descriptive county name for each code, could make this easier to read for a lay person) Your Description Here

Try to implement those improvements you mention.

# Your Code Here
ggplot(data=chi, aes(x=PWhite)) + 
geom_histogram(color = "black",fill = "blue") +
scale_y_continuous(breaks = c(5, 10, 15, 20, 40, 60, 80, 100))+
labs(x = "Percentage White", y = "Number of Tracts",
     title = "Percentage White Population in Each Tract by County",
     subtitle = "Chicago Metropolitan Region", 
     caption = "Source: US Census Bureau") +
facet_wrap(~COUNTYFP)

Now that you have a better sense of the distribution of the white population within the region, try your hand at independently visualizing other racial groups:

# Your Work Here
ggplot(data=chi, aes(x=PBlack)) + 
geom_histogram(color = "black",fill = "orange") +
scale_y_continuous(breaks = c(5, 10, 15, 20, 50, 100, 150, 200))+
labs(x = "Percentage Black", y = "Number of Tracts",
     title = "Percentage Black Population in Each Tract by County",
     subtitle = "Chicago Metropolitan Region", 
     caption = "Source: US Census Bureau") +
facet_wrap(~COUNTYFP)


ggplot(data=chi, aes(x=PLatino)) + 
geom_histogram(color = "black",fill = "green") +
scale_y_continuous(breaks = c(5, 10, 30, 50, 70, 100))+
labs(x = "Percentage Latino", y = "Number of Tracts",
     title = "Percentage Latino Population in Each Tract by County",
     subtitle = "Chicago Metropolitan Region", 
     caption = "Source: US Census Bureau") +
facet_wrap(~COUNTYFP)

Measuring Racial Segregation

Now that we have a basic idea of the racial distribution for census tracts within the region, we can start to think about summary measures of the extent to which these groups are segregated within the region. We will use census tracts as a unit of analysis to help us describe county-level racial segregation.

Dissimilarity

Dissimilarity is a common measure of evenness between two populations - dissimilarity measures the distribution of a minority population within a majority population. Conceptually, dissimilarity measures the proportion of that minority or subgroup population that would need to move in order to be equally distributed with the majority population. Dissimilarity is calculated as follows:

\(D = .5*\sum_i |\frac{b_i}{B}-\frac{w_i}{W}|\) where \(b_i\) is the number of blacks in tract i \(B\) is the number of blacks for the county \(w_i\) is the number of whites in tract i \(W\) is the number of whites for the county

Now that we know the formula, we can start thinking about how to translate this into dplyr notation.

Black-White Dissimilarity

This looks complicated, but we can actually do this fairly simply with dplyr notation. Let’s start off by calculating Black-White dissimilarity.

We have our white and black tract population data already in our il_trt data, and we have our county data in a separate object. Let’s go ahead and join that county data to our tract data.

chi<-left_join(chi, co %>% st_set_geometry(NULL), by="COUNTYFP")

Notice that this join looks pretty standard with the exception of st_set_geometry(NULL). The county level data has spatial geometry associated with it that we do not necessarily want to join to our tract-level data since that has its own geometry as well. st_set_geometry(NULL) removes the geometry from the county data, basically turning it into a plain old data table.

Now that we’ve joined that, we can start breaking down the dissimilarity formula into code-able pieces. Inside the absolute value we are calculating fractions of tract minority and majority populations compared to their county. We then subtract these from each other and use abs() to find the absolute value. After that, we need to sum these all up and multiply by .5. We are calculating these by county, so we can use group_by() to sum up only the data for each county to produce a series of final dissimilarity statistics for each county in the Chicago metropolitan area.

chi %>% mutate(dissim_wb = abs(Black / Black_co - White / White_co)) %>% group_by(COUNTYFP) %>% summarise(dissimilarity = .5*sum(dissim_wb))
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Simple feature collection with 9 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

How would you interpret these black-white dissimilarity values? Where is Black-White dissimilarity the highest within the region? Where is it the lowest?

Your turn - calculate nonwhite-white dissimilarity and Latino-white dissimilarity measures for the counties in the Chicago metropolitan area.

Nonwhite-White Dissimilarity

# Your Code Here
 chi %>% mutate(dissim_wnw = abs(Nonwhite /Nonwhite_co - White / White_co)) %>% group_by(COUNTYFP) %>% summarise(dissimilarity = .5*sum(dissim_wnw))
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Simple feature collection with 9 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

Compare and contrast this with Black-White dissimilarity, and write down your thoughts.

Your Thoughts Here Counties are mostly less dissimilar in the nonwhite-white category than the black-white category. ## Latino-White Dissimilarity

# Your Code Here
 chi %>% mutate(dissim_lw = abs(Latino /Latino_co - White / White_co)) %>% group_by(COUNTYFP) %>% summarise(dissimilarity = .5*sum(dissim_lw))
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Simple feature collection with 9 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

Compare and contrast this with Black-White dissimilarity, and write down your thoughts.

Your Thoughts Here This is also less dissimilar than the Black-White section.

Interaction

A second common measure of segregation is interaction which is a measure of exposure. Interaction measures the likelihood of population subgroups interacting with one another based upon their distribution within areal sub units (tracts). For instance, Black-White interaction is calculated as follows:

\(Interaction = \sum_i\frac{b_i}{B}*\frac{w_i}{t_i}\) Where \(b_i\) is the Black population of tract i \(B\) is the Black population of the county \(w_i\) is the White population of tract i \(t_i\) is the total population of tract i

Given that there are some similarities to the dissimilarity index, modify your existing code to measure Black White interaction for counties in the Chicago Metropolitan Area:

# Your Code Here
chi %>% mutate(inter_wb = abs((Black / Black_co) * (White / Pop))) %>% group_by(COUNTYFP) %>% summarise(interaction = sum(inter_wb, na.rm = TRUE))
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Simple feature collection with 9 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

The output here is actually a probability that ranges from 0 to 1. A value closer to 1 indicates a higher probability of there being contact between these two population groups. A value closer to 0 indicates lower probabilities of contact.

Provide your interpretation of Black-White Interaction for Chicago metro counties. Cook has the lowest probability of interaction by far, while Grundy and McHenry have much higher rates of interaction. These two are both over 90% white, it is worth mentioning. Now go ahead and calculate Non-White - White Interaction.

# Your Code Here
chi %>% mutate(inter_wnw = abs((Nonwhite / Nonwhite_co) * (White / Pop))) %>% group_by(COUNTYFP) %>% summarise(interaction = sum(inter_wnw, na.rm = TRUE))
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Simple feature collection with 9 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

Finally, go ahead and calculate Latino - White Interaction.

# Your Code Here
chi %>% mutate(inter_wl = abs((Latino / Latino_co) * (White / Pop))) %>% group_by(COUNTYFP) %>% summarise(interaction = sum(inter_wl, na.rm = TRUE))
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Simple feature collection with 9 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

How would you interpret Black-White, Non-White White, and Latino-White interaction jointly? Across the board, the Latino-White interactions are most probable.

Isolation

The final measure of racial segregation we’ll look at in this lab is isolation which is only measured for one group at a time. Isolation measures the likelihood of contact for a subgroup with other subgroup members. It is interpreted similarly to Interaction (as a probability ranging from 0 to 1):

Isolation for Blacks \(Isolation = \sum_i\frac{b_i}{B}*\frac{b_i}{t_i}\) Where \(b_i\) is the Black population of tract i \(B\) is the Black population of the county \(t_i\) is the total population of tract i

Modify your existing code to calculate Black Isolation by county for the Chicago Metropolitan Area:

# Your Code Here
chi %>% mutate(iso_b = abs((Black / Black_co) * (Black / Pop))) %>% group_by(COUNTYFP) %>% summarise(isolation = sum(iso_b, na.rm = TRUE))
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Simple feature collection with 9 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

You know what comes next. Calculate Nonwhite Isolation and Latino Isolation and interpret what you see.

Nonwhite Isolation

# Your Code Here
chi %>% mutate(iso_nw = abs((Nonwhite / Nonwhite_co) * (Nonwhite / Pop))) %>% group_by(COUNTYFP) %>% summarise(isolation = sum(iso_nw, na.rm = TRUE))
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Simple feature collection with 9 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

Latino Isolation

# Your Code Here
chi %>% mutate(iso_l = abs((Latino / Latino_co) * (Latino / Pop))) %>% group_by(COUNTYFP) %>% summarise(isolation = sum(iso_l, na.rm = TRUE))
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Simple feature collection with 9 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -88.94215 ymin: 41.10828 xmax: -87.52366 ymax: 42.49564
geographic CRS: NAD83

Income Inequality

While we’re at it, let’s also pay attention to segregation on the basis of income. A simple measure of income inequality and distribution is to calculate the difference in median income between the county and the census tracts that make up the county.

We have all of our census tract data, but need to go back to census data to download county median household income for each county in the Chicago metro area (this is not a place to take the average or weighted average of the tract-level data). Go ahead and download those data and prepare them for joining to our tract data:

# Your Code Here
B19013<-get_acs(geography = "county", state = state, variables = B19013_Vars, survey = survey, year = DL_Year, output = "wide")
Getting data from the 2015-2019 5-year ACS
Using FIPS code '17' for state 'IL'
B19013$MHHI_co<-B19013$B19013_001E
B19013$MHHI_co[B19013$MHHI_co == "NaN"]<-NA
B19013<-B19013 %>% select(GEOID, MHHI_co)

Now start thinking about how you’ll accomplish this join. The county-level data have a GEOID that includes the combined state and county FIPS codes (e.g. “17031”) means Illinois - Cook County. Your tract-level data lists the State and County FIPS codes separately, but not together. Right now, you don’t have a common field to join on.

Given that we conveniently have separate state (STATEFP) and county (COUNTYFP) codes, we can concatenate these together into a code that will match up to the GEOID field in our county median household income data:

chi<-chi %>% mutate(COUNTY = paste0(STATEFP, COUNTYFP))

Recall that paste0() pastes fields together with no spaces between them.

Okay now you’re on track to go ahead and join the county-level median household income data to your tract-level data. Do so, but remember that your by= field will look a bit different since the matching fields have different names in the two datasets:

# Your Work Here
chi <- left_join(chi, B19013, by =c("COUNTY" = "GEOID"))

Now we can calculate the ratio of income for our census tract to that of the county:

chi<-chi %>% mutate(inc_ratio = MHHI / MHHI_co)

Now go ahead and map out this income ratio statistic for the Chicago Metropolitan Area:

# Your Code Here
ggplot()+
  geom_sf(data = chi, aes(fill=inc_ratio), colour = NA) +
   labs(title = "Income Ratio for the Chicago Region", fill = "Income Ratio")+
  geom_sf(data=co, fill=NA) +
  theme_minimal()

What would a ratio of 1 indicate? What would a ratio of 4 indicate? Where do we see big differences? A Ratio of 1 means the tract has the same median income as the county, while a ratio of 4 suggests that the tract has a much higher median income than the whole. Unsurprisingly, Cook also has the highest visual variance.

While we’re at it, it might be interesting to create a scatter plot that illustrates the relationship between racial concentration and income. Give that a try (plot the Percent White on the X axis and the income ratio on the y axis using geom_point):

ggplot()+
  geom_point(data=chi, aes(x=PWhite, y=inc_ratio)) +
  labs(title = "My Cool Plot", x = "Percent White", y = "Income Ratio")

How would you describe this relationship? It is positive- the higher median income of a tract in respect to the county, the larger the proportion of white residents

Now see if you can add a linear line of best fit to these data using geom_smooth (you’ll need to set method = lm to get a fitted linear model):

# Your Code Here
ggplot()+
  geom_point(data=chi, aes(x=PWhite, y=inc_ratio)) +
  geom_smooth(data=chi, method= lm, aes(x=PWhite, y=inc_ratio)) +
  labs(title = "My Cool Plot", x = "Percent White", y = "Income Ratio")

What’s the relationship between the percent white population and the income ratio? Positive, as one rises, so does the other.

What would it look like to split this out by counties using facets?

# Your Code Here
ggplot()+
  geom_point(data=chi, aes(x=PWhite, y=inc_ratio)) +
  geom_smooth(data=chi, method= lm, aes(x=PWhite, y=inc_ratio)) +
  labs(title = "My Cool Plot", x = "Percent White", y = "Income Ratio")+
  facet_wrap(~COUNTYFP)

Congratulations, you have learned some ways to calculate common measures of segregation, and have applied these measures as part of a data pipeline.

By changing your download calls at the very beginning of this lab where you download acs data, you could easily create segregation measures for other places. See what you need to do to modify the code to run for another metropolitan area or county.

Extending this Lab

Now that you have some new tools that you are familiar with, start exploring these data more. Make maps for other racial groups. Explore dimensions of segregation for other groups.

  1. Can you produce the data which would populate a summary table of minority-majority dissimilarity? Which groups face the highest levels of segregation?

  2. How does income relate to levels of segregation? Think about how you might use the median household income statistic to explore the relationship.

  3. What are other forms of segregation that might be useful to explore (aside from racial and income segregation)?

LS0tDQp0aXRsZTogIkxhYiBCb29rICMyLSBTZWdyZWdhdGlvbiBpbiBDaGljYWdvIg0KYXV0aG9yOiAiV2lsbCBGaW5rZWxzdGVpbiwgTVVQMSINCmRhdGU6ICIzLzkvMjAyMSINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogeWVzDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojIEludHJvZHVjdGlvbg0KVHdvIHdlZWtzIGFnbywgeW91IHNwZW50IHNvbWUgdGltZSBsZWFybmluZyBhYm91dCB3YXlzIHRvIG1lYXN1cmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcG9wdWxhdGlvbiBieSByYWNlIGFuZCBldGhuaWNpdHkuIFRoaXMgbGFiIGJ1aWxkcyB1cG9uIHRoYXQgcGFzdCBrbm93bGVkZ2UsIHByaW1hcmlseSBieSBoZWxwaW5nIHlvdSB0byB2aXN1YWxpemUgYW5kIGFuYWx5emUgdGhlc2UgZGlzdHJpYnV0aW9ucyBzcGF0aWFsbHkuDQoNCiMjIERlc2NyaXB0aW9uIGFuZCBHb2Fscw0KSW4gdGhpcyBsYWIsIHdlIHdpbGwgdXNlIEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkgZGF0YSB0byBwZXJmb3JtIHNvbWUgZXhwbG9yYXRvcnkgZGF0YSB2aXN1YWxpemF0aW9uIGZvciB0aGUgQ2hpY2FnbyBNZXRyb3BvbGl0YW4gQXJlYSwgZm9jdXNpbmcgb24gZGVzY3JpYmluZyByZXNpZGVudGlhbCBzZWdyZWdhdGlvbiBiYXNlZCB1cG9uIHJhY2UgYW5kIGluY29tZS4gT3VyIGdvYWxzIGZvciB0aGlzIGxhYiBhcmUgYXMgZm9sbG93czoNCg0KLSBDb250aW51ZSB0byBnYWluIGV4cGVyaWVuY2Ugd2l0aCBgdGlkeWNlbnN1c2AgYW5kIGBnZ3Bsb3RgDQotIExlYXJuIHNvbWUgYWRkaXRpb25hbCBxdWFsaXRpZXMgb2Ygc2ltcGxlIGZlYXR1cmUgZ2VvbWV0cmllcywgd2hpY2ggYWxsb3dzIFIgdG8gbWFuaXB1bGF0ZSBzcGF0aWFsIGRhdGENCi0gR2FpbiBtb3JlIGV4cGVyaWVuY2Ugd2l0aCBgZ2VvbV9zZigpYCBhbmQgbWFwcGluZyBzaW1wbGUgZmVhdHVyZSBnZW9tZXRyaWVzDQotIEFwcGx5IHNldmVyYWwgbWVhc3VyZXMgb2Ygc3BhdGlhbCBzZWdyZWdhdGlvbiB0byBhbmFseXplIHJlZ2lvbmFsIHBhdHRlcm5zDQoNCkJ5IHRoZSBlbmQgb2YgdGhpcyBsYWIsIHlvdSB3aWxsIGltcGxlbWVudCBhIGRhdGEgcGlwZWxpbmUgdG8gcHJvZ3JhbW1hdGljYWxseSBkb3dubG9hZCwgbWFwLCBhbmQgZGVzY3JpYmUgZWxlbWVudHMgb2YgcmVzaWRlbnRpYWwgc2VncmVnYXRpb24gZm9yIGEgY2l0eSBhbmQgaXRzIHJlZ2lvbi4NCg0KIyMgU2V0IFVwIFdvcmtzcGFjZQ0KDQpMZXQncyBnbyBhaGVhZCBhbmQgcHJvZ3JhbW1hdGljYWxseSBjcmVhdGUgYSBmZXcgZGlyZWN0b3JpZXMgdG8gaGVscCB1cyBrZWVwIG91ciB3b3Jrc3BhY2Ugb3JnYW5pemVkLiBZb3UnbGwgcmVjYWxsIHRoYXQgd2UgbGVhcm5lZCBob3cgdG8gdXNlIGBkaXIuY3JlYXRlKClgIGluIHRoZSBwYXN0IHRvIGluc2VydCBuZXcgZGlyZWN0b3JpZXMgaW50byBvdXIgImhvbWUiIGRpcmVjdG9yeSB3aGljaCBpcyBzZXQgYmFzZWQgdXBvbiB3aGVyZSBvdXIgcHJvamVjdCAuUm1kIGZpbGUgaXMgbG9jYXRlZC5JbiB0aGlzIGNhc2UsIHdlJ2xsIGNyZWF0ZSB0aGUgdHlwaWNhbCBmb2xkZXJzIHdlIHdvcmsgd2l0aCB0byBrZWVwIG91ciBsYWJzIG9yZ2FuaXplZCAtIGRhdGEsIGRvY3VtZW50YXRpb24sIG91dHB1dCwgYW5kIHNjcmlwdHMuDQoNCmBgYHtyfQ0KZGlyLmNyZWF0ZSgiZGF0YSIpDQpkaXIuY3JlYXRlKCJkb2N1bWVudGF0aW9uIikNCmRpci5jcmVhdGUoIm91dHB1dCIpDQpkaXIuY3JlYXRlKCJzY3JpcHRzIikNCmBgYA0KDQojIyBMb2FkIFJlcXVpcmVkIFBhY2thZ2VzDQpMZXQncyBzdGFydCBieSBsb2FkaW5nIHRoZSBgdGlkeXZlcnNlYCBhbmQgYHRpZHljZW5zdXNgIHBhY2thZ2VzLiBZb3UgY2FuIGFkZCBvdGhlciBwYWNrYWdlcyBoZXJlIGFzIHdlIG5lZWQgdGhlbSBzbyB0aGF0IHRoZXkgbG9hZCBhdCB0aGUgYmVnaW5uaW5nIG9mIG91ciBub3RlYm9vay4NCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodGlkeWNlbnN1cykNCmNlbnN1c19hcGlfa2V5KCJmNmQzZjMwOGYwMGEwZmZkYTNhYTE5ZTg2ODA3ZTBlYTU5NjBkODZlIiwgaW5zdGFsbCA9IFRSVUUsIG92ZXJ3cml0ZT1UUlVFKQ0KYGBgDQoNCiMgRG93bmxvYWQgQ2Vuc3VzIERhdGENCg0KIyMgRG93bmxvYWQgQUNTIERhdGENCg0KTm93IGxldCdzIGdvIGFoZWFkIGFuZCBkb3dubG9hZCBzb21lIGNlbnN1cyBkYXRhIHdoaWNoIHdlJ2xsIHVzZSB0byBjYWxjdWxhdGUgc2VncmVnYXRpb24gbWVhc3VyZXMgd2l0aC4gRm9yIHRoaXMgbGFiLCB3ZSdsbCBkb3dubG9hZCB0aGUgZGF0YSBhdCB0aGUgY2Vuc3VzIHRyYWN0IGxldmVsIGZvciBhbGwgdHJhY3RzIGluIElsbGlub2lzIChsYXRlciBvbiwgd2UnbGwgcHVsbCBvdXQgcGVydGluZW50IGNvdW50aWVzIGluIHRoZSBDaGljYWdvIG1ldHJvcG9saXRhbiBzdGF0aXN0aWNhbCBhcmVhKS4gTGV0J3MgY2FsY3VsYXRlIHRoZSBmb2xsb3dpbmcgbWVhc3VyZXM6DQoNCnwgQUNTIFRhYmxlIHwgVmFyaWFibGVzICAgICAgICAgICAgICAgIHwgTGFiZWwgICAgfCBEZXNjcmlwdGlvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfC0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8IEIwMTAwMSAgICB8IEIwMTAwMV8wMDFFICAgICAgICAgICAgICB8IFBvcCAgICAgIHwgVG90YWwgUG9wdWxhdGlvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgQjAyMDAxICAgIHwgQjAyMDAxXzAwMkUgICAgICAgICAgICAgIHwgV2hpdGUgICAgfCBDb3VudCBvZiBXaGl0ZSBQb3B1bGF0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBCMDIwMDEgICAgfCBCMDIwMDFfMDAzRSAgICAgICAgICAgICAgfCBCbGFjayAgICB8IENvdW50IG9mIEJsYWNrIFBvcHVsYXRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IEIwMjAwMSAgICB8IEIwMjAwMV8wMDRFICAgICAgICAgICAgICB8IEFJQU4gICAgIHwgQ291bnQgb2YgQW1lcmljYW4gSW5kaWFuIGFuZCBBbGFza2FuIE5hdGl2ZSBQb3B1bGF0aW9uIHwNCnwgQjAyMDAxICAgIHwgQjAyMDAxXzAwNUUgICAgICAgICAgICAgIHwgQXNpYW4gICAgfCBDb3VudCBvZiBBc2lhbiBQb3B1bGF0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBCMDIwMDEgICAgfCBCMDIwMDFfMDAxRSwgQjAyMDAxXzAwMkUgfCBOb253aGl0ZSB8IENvdW50IG9mIE5vbndoaXRlIFBvcHVsYXRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IEIwMzAwMSAgICB8IEIwMzAwMV8wMDNFICAgICAgICAgICAgICB8IExhdGlubyAgIHwgQ291bnQgb2YgTGF0aW5vIFBvcHVsYXRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgQjE5MDEzICAgIHwgQjE5MDEzXzAwMUUgICAgICAgICAgICAgIHwgTUhISSAgICAgfCBNZWRpYW4gSG91c2Vob2xkIEluY29tZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KDQpJIGFtIGdvaW5nIHRvIGRvIHlvdSBhIGZhdm9yIC0gSSBoYXZlIHdyaXR0ZW4gYSBzY3JpcHQgdGhhdCB3aWxsIGRvd25sb2FkIHRoZXNlIHZhcmlhYmxlcyBmb3IgeW91LiBJbiBvcmRlciBmb3IgaXQgdG8gd29yaywgeW91IHdpbGwgbmVlZCB0byBzdXBwbHkgdGhlIHNjcmlwdCB3aXRoIHNvbWUgdmFyaWFibGVzLCBuYW1lbHkgeW91ciBjZW5zdXMgQVBJIGtleSwgdGhlIGRvd25sb2FkIHllYXIsIHRoZSBnZW9ncmFwaGljIHN1bW1hcnkgbGV2ZWwgeW91IHdpc2ggdG8gZG93bmxvYWQsIHRoZSBzdGF0ZSwgYW5kIHRoZSBBQ1Mgc3VydmV5IHByb2R1Y3QgeW91IHdpc2ggdG8gZG93bmxvYWQuIExldCdzIGRvd25sb2FkIDIwMTkgNS15ZWFyIEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkgZGF0YS4gDQoNCi0gYXBpX2tleTogWW91ciBDZW5zdXMgQVBJIEtleQ0KLSBETF9ZZWFyOiBUaGUgZW5kIHllYXIgZm9yIHRoZSBkYXRhIHlvdSB3aXNoIHRvIGRvd25sb2FkDQotIHN1cnZleTogVGhlIG5hbWUgb2YgdGhlIHN1cnZleSB5b3Ugd2lzaCB0byBkb3dubG9hZCAodGhpcyBjb3VkIGJlICJhY3MxIiwgImFjczMiLCBvciAiYWNzNSIpDQotIGdlbzogVGhlIGdlb2dyYXBoaWMgc3VtbWFyeSBsZXZlbCB5b3Ugd2lzaCB0byBkb3dubG9hZCAoZm9sbG93aW5nIGB0aWR5Y2Vuc3VzYCBub21lbmNsYXR1cmUpDQotIHN0YXRlOiBUaGUgbmFtZShzKSBvZiB0aGUgc3RhdGUocykgeW91IHdpc2ggdG8gZG93bmxvYWQgZGF0YSBmb3IuIA0KDQpgYGB7cn0NCiMgWW91ciBXb3JrIEhlcmUNCmFwaV9rZXk8LSJmNmQzZjMwOGYwMGEwZmZkYTNhYTE5ZTg2ODA3ZTBlYTU5NjBkODZlIg0KRExfWWVhcjwtMjAxOQ0Kc3VydmV5IDwtICJhY3M1Ig0KZ2VvPC0idHJhY3QiDQpzdGF0ZTwtYygiSUwiKQ0KDQpgYGANCg0KSWYgeW91IGxvb2sgaW4gdGhlIGxhYiBmb2xkZXIsIHRoZXJlIGlzIGEgc2NyaXB0IGNhbGxlZCAiMV9HZXRfQUNTLlIiDQoNClRha2UgYSBsb29rIGF0IGhvdyB0aGUgYGdldF9hY3MoKWAgY2FsbCBpcyBzZXQgdXAgd2l0aGluIHRoZSBzY3JpcHQuIFdoYXQncyBnb2luZyBvbiBoZXJlPw0KDQoqWW91ciBEZXNjcmlwdGlvbioNCg0KV2UgY2FuIGFzayBSIHRvIHJ1biB0aGlzIGVudGlyZSBzY3JpcHQgZm9yIHVzIHVzaW5nIHRoZSBgc291cmNlKClgIGNvbW1hbmQuIE1ha2Ugc3VyZSB5b3VyIHZhcmlhYmVzIGFyZSBjb3JyZWN0bHkgc2V0IHVwIGFib3ZlIGJlZm9yZSBydW5uaW5nOg0KYGBge3J9DQpzb3VyY2UoIjFfR2V0X0FDUy5SIikNCmBgYA0KDQpSIGlzIHJ1bm5pbmcgYWxsIG9mIHRoZSBjb2RlIGNvbnRhaW5lZCBpbiB0aGF0IHNjcmlwdCB3aXRob3V0IHVzIGhhdmluZyB0byBvcGVuIGl0LiBJdCBzdGFydHMgYXQgdGhlIGJlZ2lubmluZyBhbmQgcnVucyB1bnRpbCBpdCByZWFjaGVzIHRoZSBlbmQgb2YgdGhlIHNjcmlwdC4gVGhpcyBjYW4gYmUgdXNlZnVsIGZvciBjcmVhdGluZyBjb2RlIHN1Yi1jb21wb25lbnRzIHRoYXQgeW91IGNhbiBydW4gZnJvbSB3aXRoaW4gb3RoZXIgc2NyaXB0cyBvciBub3RlYm9va3MuIA0KDQpZb3Ugbm93IGhhdmUgYSBkYXRhc2V0IGNhbGxlZCBhY3NfZGF0YSBjb250YWluaW5nIDMsMTIzIG9ic2VydmF0aW9ucyBvZiAxNSB2YXJpYWJsZXMuIFRoZXNlIHZhcmlhYmxlcyBpbmNsdWRlIHRoZSBwb3B1bGF0aW9uIChQb3ApLCBQb3B1bGF0aW9uIGJ5IHJhY2UgYW5kIGV0aG5pY2l0eSwgYW5kIHRoZSBtZWRpYW4gaG91c2Vob2xkIGluY29tZSAoTUhISSkgZm9yIGVhY2ggY2Vuc3VzIHRyYWN0LiBJJ3ZlIGFsc28gY2FsY3VsYXRlZCBmb3IgeW91IHRoZSBwZXJjZW50IG9mIHRoZSBwb3B1bGF0aW9uIGJ5IHJhY2UgYW5kIGV0aG5pY2l0eSAoeW91IHNob3VsZCBjaGVjayB0aGUgc2NyaXB0IHRvIHNlZSBob3cgdGhpcyB3YXMgZG9uZSkuIE9rIC0gd2UgaGF2ZSBvdXIgQUNTIGRhdGEuIA0KDQojIERvd25sb2FkIEdlb2dyYXBoaWMgRGF0YQ0KDQpOZXh0LCBsZXQncyBhbHNvIGRvd25sb2FkIHNwYXRpYWwgZGF0YSBhc3NvY2lhdGVkIHdpdGggdHJhY3QgZ2VvZ3JhcGhpZXMuDQoNClRoZSBgdGlncmlzYCBwYWNrYWdlIGlzIGRlc2lnbmVkIHRvIGRvd25sb2FkIGRhdGEgZGlyZWN0bHkgZnJvbSB0aGUgY2Vuc3VzIEFQSS4gVW5saWtlIHRoZSBgdGlkeWNlbnN1c2AgcGFja2FnZSwgaXQgZG9lcyBub3QgcmVxdWlyZSBhbiBBUEkga2V5LiBgdGlncmlzYCBjYW4gZG93bmxvYWQgZ2VvZ3JhcGhpZXMgYXMgc2hhcGVmaWxlcyAoYSBmb3JtYXQgY29tbW9ubHkgdXNlZCBieSBjb21tZXJjaWFsIEdJUyBwcm9ncmFtcyBsaWtlIEFyY0dJUyksIGJ1dCBldmVuIG1vcmUgY29udmVuaWVudGx5LCBpdCBjYW4gZG93bmxvYWQgdGhlc2UgZGF0YSBpbiBhIGZvcm1hdCBjYWxsZWQgKnNpbXBsZSBmZWF0dXJlcyouIA0KDQpBcyB5b3Ugc2hvdWxkIHJlY2FsbCBmcm9tIG91ciBsYXN0IHNlc3Npb24sIFNpbXBsZSBGZWF0dXJlcyAodGhlIHNmIHBhY2thZ2UpIHN0b3JlIGdlb2dyYXBoaWMgYXR0cmlidXRlcyBhcyByb3dzIGluIGEgdGFibGUsIHdpdGggYSBzcGVjaWFsIGFkZGl0aW9uYWwgcm93IGNhbGxlZCBnZW9tZXRyeSB3aGljaCBzdG9yZXMgdGhlIGNvb3JkaW5hdGVzIGFzc29jaWF0ZWQgd2l0aCB0aGUgZ2VvZ3JhcGh5LiBUaGVzZSBjb29yZGluYXRlcyBhcmUgc3RvcmVkIGFzIGEgbGlzdCB3aGljaCBSIGNhbiB0aGVuIHJlY2FsbCBhbmQgcGxvdCBvdXQuIFlvdSBjYW4gcmVhZCBtb3JlIGFib3V0IGhvdyBzaW1wbGUgZmVhdHVyZXMgYXJlIG9yZ2FuaXplZCBbaGVyZV0oaHR0cHM6Ly9yLXNwYXRpYWwuZ2l0aHViLmlvL3NmL2FydGljbGVzL3NmMS5odG1sKS4NCg0KTGV0J3MgZG93bmxvYWQgY2Vuc3VzIHRyYWN0cyBmb3IgSWxsaW5vaXMgYW5kIHRha2UgYSBsb29rLiBUaWdyaXMgY2FuIGRvd25sb2FkIGEgcmFuZ2Ugb2YgZ2VvZ3JhcGh5IHR5cGVzLiBXZSBjYW4gdXNlIHRoZSBgdHJhY3RzKClgIGZ1bmN0aW9uIHRvIGRvd25sb2FkIHRyYWN0cy4gV2Ugc3BlY2lmeSBhIHN0YXRlIGFuZCBhbHNvIHNwZWNpZnkgdGhhdCB3ZSB3YW50IHRpZ3JpcyB0byBkb3dubG9hZCB0aGUgc3BhdGlhbCBpbmZvcm1hdGlvbiBpbiBzaW1wbGUgZmVhdHVyZSBmb3JtYXQgYGNsYXNzPSJzZiJgLg0KDQpMb2FkIGJvdGggdGhlIHRpZ3JpcyBhbmQgc2YgcGFja2FnZSBhbmQgZG93bmxvYWQgdHJhY3RzIGZvciBJbGxpbm9pcyBpbnRvIGFuIG9iamVjdCBjYWxsZWQgaWxfdHJ0Lg0KDQpgYGB7cn0NCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KHRpZ3JpcykNCmlsX3RydDwtdHJhY3RzKHN0YXRlPSJJTCIsIGNsYXNzPSJzZiIpDQpgYGANCg0KVGFrZSBhIGxvb2sgYXQgdGhlIHRyYWN0IGRhdGEgLSBlYWNoIHJvdyBpcyBhIGNlbnN1cyB0cmFjdC4gVGhlcmUgYXJlIG11bHRpcGxlIGNvbHVtbnMgZGVzY3JpYmluZyBlYWNoIHRyYWN0LiBUaGUgZ2VvbWV0cnkgY29sdW1uIGNvbnRhaW5zIGNvb3JkaW5hdGVzLg0KDQpDb25maXJtIHRoYXQgeW91IGdvdCB3aGF0IHlvdSB3ZXJlIGV4cGVjdGluZyBieSBwbG90dGluZyB0aGVzZSBkYXRhLiBSZW1lbWJlciB0aGF0IGluIGdncGxvdCwgeW91IGNhbiB1c2UgYGdlb21fc2YoKWAgdG8gcGxvdC4gSXQgd2lsbCB0YWtlIGEgbW9tZW50IHRvIHBsb3QsIGFzIGl0IGlzIHJlbmRlcmluZyBsb3RzIG9mIGRldGFpbCBmb3IgZWFjaCBjZW5zdXMgdHJhY3QgaW4gSWxsaW5vaXM6DQoNCmBgYHtyfQ0KIyBZb3VyIENvZGUgSGVyZQ0KZ2dwbG90KCkgKyBnZW9tX3NmKGRhdGE9aWxfdHJ0KQ0KYGBgDQpUaGlzIHBsb3QgbG9va3Mgcm91Z2hseSBsaWtlIHRoZSBzdGF0ZSBvZiBJbGxpbm9pcyAtIGdvb2QgZW5vdWdoIHRvIGZlZWwgY29tZm9ydGFibGUgd2l0aCBtb3ZpbmcgZm9yd2FyZC4NCg0KR28gYWhlYWQgYW5kIGpvaW4gdGhlIEFDUyBkYXRhIGNvbnRhaW5lZCBpbiBhY3NfZGF0YSBkYXRhICp0byogdGhlIHRyYWN0IGRhdGEgY29udGFpbmVkIGluIGlsX3RydC4gVGhlIGNvbW1vbiBmaWVsZCBiZXR3ZWVuIHRoZSB0d28gaXMgR0VPSUQuIA0KDQpgYGB7cn0NCiMgWW91ciBDb2RlIEhlcmUNCmlsX3RydCA8LSBsZWZ0X2pvaW4oaWxfdHJ0LCBhY3NfZGF0YSwgYnkgPSAiR0VPSUQiKQ0KYGBgDQoNCiMgUmUtaW50cm9kdWNpbmcgZ2VvbV9zZigpDQoNCldlIGhhdmUgbm90IHByb2dyYW1tYXRpY2FsbHkgZG93bmxvYWRlZCBnZW9ncmFwaGljIGFuZCB0cmFjdCBhdHRyaWJ1dGUgZGF0YSBhbmQgam9pbmVkIHRoZW0gdG9nZXRoZXIuIExldCdzIHZlbnR1cmUgaW50byB1c2luZyBSIGFzIGEgd2F5IHRvIHZpc3VhbGl6ZSBzcGF0aWFsIGRhdGEuDQoNCkxhc3Qgd2VlaywgeW91IGJlZ2FuIGV4cGxvcmluZyB0aGUgdmlzdWFsaXphdGlvbiBmZWF0dXJlcyBvZiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuIExldCdzIGNvbnRpbnVlIHRvIGJ1aWxkIG9uIHRoaXMgYnkgcGxvdHRpbmcgb3VyIGRhdGEgY29udGFpbmluZyBzaW1wbGUgZmVhdHVyZSBnZW9tZXRyaWVzLiBXZSdyZSBnb2luZyB0byBmb2N1cyBzcGVjaWZpY2FsbHkgb24gdW5kZXJzdGFuZGluZyBkaW1lbnNpb25zIG9mIHNlZ3JlZ2F0aW9uIGZvciBjZW5zdXMgdHJhY3RzIGluIHRoZSBDaGljYWdvIG1ldHJvcG9saXRhbiBhcmVhLg0KDQpMZXQncyBnbyBhaGVhZCBhbmQgc2VsZWN0IGEgc3Vic2V0IG9mIHRoZXNlIGRhdGEgLSB0aGUgY2Vuc3VzIHRyYWN0cyBmb3IgdGhlIGNvdW50aWVzIHRoYXQgbWFrZSB1cCB0aGUgSWxsaW5vaXMgcG9ydGlvbiBvZiB0aGUgQ2hpY2FnbyBNZXRyb3BvbGl0YW4gQXJlYS4gRm9yIHlvdXIgY29udmVuaWVuY2UsIGhlcmUncyB0aGUgbmFtZXMgb2YgdGhvc2UgY291bnRpZXMgYW5kIHRoZWlyIGFzc29jaWF0ZWQgY291bnR5IEZJUFMgY29kZXM6DQoNCnwgQ291bnR5ICB8IEZJUFMgfA0KfC0tLS0tLS0tLXwtLS0tLS18DQp8IENvb2sgICAgfCAwMzEgIHwNCnwgRGVLYWxiICB8IDAzNyAgfA0KfCBEdVBhZ2UgIHwgMDQzICB8DQp8IEdydW5keSAgfCAwNjMgIHwNCnwgS2FuZSAgICB8IDA4OSAgfA0KfCBLZW5kYWxsIHwgMDkzICB8DQp8IExha2UgICAgfCAwOTcgIHwNCnwgTWNIZW5yeSB8IDExMSAgfA0KfCBXaWxsICAgIHwgMTk3ICB8DQoNCkNyZWF0ZSBhIG5ldyBvYmplY3QgY2FsbGVkICJjaGkiIHdoaWNoIGNvbnRhaW5zIHRoZSByZWNvcmRzIGZyb20gaWxfdHJ0IGZvciB0aGUgc3Vic2V0IG9mIElsbGlub2lzIGNvdW50aWVzIHRoYXQgYXJlIGluIHRoZSBDaGljYWdvIG1ldHJvcG9saXRhbiBhcmVhLiBBZnRlciB0aGlzLCBnbyBhaGVhZCBhbmQgY3JlYXRlIGEgbWFwIG9mIHRoZXNlIENoaWNhZ28gbWV0cm9wb2xpdGFuIHRyYWN0cy4NCmBgYHtyfQ0KIyBZb3VyIENvZGUgSGVyZQ0KY2hpIDwtIGlsX3RydCAlPiUgZmlsdGVyKENPVU5UWUZQICVpbiUgYygiMDMxIiwgIjAzNyIsICIwNDMiLCAiMDYzIiwgIjA4OSIsICIwOTMiLCAiMDk3IiwgIjExMSIsICIxOTciKSkNCmdncGxvdCgpICsgZ2VvbV9zZihkYXRhPWNoaSkNCg0KYGBgDQoNCk9rYXkgLSBub3cgd2UncmUgZ2V0dGluZyBzb21ld2hlcmUgLSB3ZSBjYW4gc2VlIG1vcmUgb2YgdGhlIGRlZmluaXRpb24gb2YgdGhlIHRyYWN0cy4gU29tZXRoaW5nIHNob3VsZCBnaXZlIHlvdSBwYXVzZSwgaG93ZXZlci4gVGhlcmUgYXJlIHR3byBnaWdhbnRpYyB0cmFjdHMgd2hpY2ggY292ZXIgcG9ydGlvbnMgb2YgTGFrZSBNaWNoaWdhbiBhc3NvY2lhdGVkIHdpdGggQ29vayBhbmQgTGFrZSBDb3VudGllcyAoRm9yIHRob3NlIG5vdCBmYW1pbGlhciB3aXRoIENoaWNhZ28sIENvb2sgQ291bnR5IGlzIHRoZSBjb3VudHkgaW4gd2hpY2ggQ2hpY2FnbyBpcyBsb2NhdGVkIGFuZCBMYWtlIENvdW50eSBpcyBqdXN0IG5vcnRoIG9mIGl0KS4gVGhlc2UgdHdvIHRyYWN0cyBjb250YWluIG5vIHBvcHVsYXRpb24gKHRoZXkncmUgYWxsIHdhdGVyLCBhZnRlciBhbGwpIGFuZCB3ZSBjYW4gcmVtb3ZlIHRoZW0uDQoNCkxvb2sgdGhyb3VnaCB0aGUgaWxfdHJ0IGRhdGFzZXQgYW5kIGlkZW50aWZ5IHRoZSB0d28gdHJhY3RzIGZvciB3aGljaCBBTEFORCAobGFuZCBhcmVhKSBpcyAwLiBGaWx0ZXIgdGhlc2Ugb3V0IG9mIGNoaSwgYW5kIHRoZW4gcmUtcGxvdC4NCg0KYGBge3J9DQojIFlvdXIgQ29kZSBIZXJlDQpjaGkgPC0gY2hpICU+JSBmaWx0ZXIoIUdFT0lEICVpbiUgYygiMTcwMzE5OTAwMDAiLCIxNzA5Nzk5MDAwMCIpKQ0KZ2dwbG90KCkrZ2VvbV9zZihkYXRhID0gY2hpKQ0KDQpgYGANCiMgTWFwcGluZyBSYWNlDQoNCk9rYXkgLSB3ZSd2ZSBnb3QgdGhlIGdlb2dyYXBoaWMgY29tcG9uZW50IG9mIG91ciBkYXRhIHNvcnRlZCBvdXQuIE5vdyBsZXQncyB0cnkgdmlzdWFsaXppbmcgc29tZSBvZiB0aGUgYXR0cmlidXRlcyBvZiB0aGUgZGF0YS4gV2UndmUgYWxyZWFkeSBtYXBwZWQgdGhlIHRyYWN0cyBmb3Igd2hpY2ggd2UncmUgaW50ZXJlc3RlZCBpbiBzZWVpbmcgcmFjZSBpbmZvcm1hdGlvbiBmb3IuIFRvIHZpc3VhbGl6ZSBhbiBhdHRyaWJ1dGUgb2YgdGhlIGRhdGFzZXQsIHdlIG5lZWQgdG8gYWRkIGFuIGFlc3RoZXRpYyBtYXBwaW5nIHVzaW5nIGBhZXMoKWAuIEluIHRoaXMgY2FzZSwgd2Ugd2FudCB0byBzcGVjaWZ5IHRoYXQgdGhlIGZpbGwgY29sb3IgZm9yIGVhY2ggb2Ygb3VyIGNlbnN1cyB0cmFjdHMgY29tZXMgZnJvbSBhIHBhcnRpY3VsYXIgdmFyaWFibGUgKGNvbHVtbikgZnJvbSB0aGUgaWxfdHJ0IGRhdGEgdGFibGUuIExldCdzIHN0YXJ0IGJ5IHZpc3VhbGl6aW5nIHRoZSBQV2hpdGUgKHBlcmNlbnQgd2hpdGUpIGRhdGE6DQoNCmBgYHtyfQ0KZ2dwbG90KCkrZ2VvbV9zZihkYXRhPWNoaSwgYWVzKGZpbGwgPSBQV2hpdGUpKQ0KYGBgDQpPa2F5IC0gd2UgaGF2ZSBhIG1hcCB0aGF0IG5vdyBhbHNvIGluY2x1ZGVzIGEgbGVnZW5kIGZvciBvdXIgY29udGludW91cyB2YXJpYWJsZSAocGVyY2VudGFnZSB3aGl0ZSkuIFdlIGFsc28gaGF2ZSBhIGZldyB0cmFjdHMgdGhhdCBhcmUgZ3JheWVkIG91dCAtIHRoZXkgaGF2ZSBubyBwb3B1bGF0aW9uIChub3RpY2UgdGhhdCBvbmUgb2YgdGhlc2UgaXMgTydIYXJlIGFpcnBvcnQpLiANCg0KT25lIGNoYWxsZW5nZSBoZXJlIGlzIHRoYXQgYXQgdGhpcyBzY2FsZSwgdGhlIHRyYWN0IGJvdW5kYXJpZXMgKGdyYXkgbGluZXMpIG9ic2N1cmUgc29tZSBvZiB0aGUgY2Vuc3VzIHRyYWN0IGRhdGEuIFdlIGNvdWxkIHNldCB0aGUgbGluZSBjb2xvciAoY2Vuc3VzIHRyYWN0IGJvdW5kYXJ5KSB0byBiZSB0aGUgc2FtZSBhcyB0aGUgZGF0YSBmb3IgaXRzIHJlc3BlY3RpdmUgdHJhY3QgdXNpbmcgdGhlIGNvbG91ciBhZXN0aGV0aWMgbWFwcGluZzoNCg0KYGBge3J9DQpnZ3Bsb3QoKStnZW9tX3NmKGRhdGE9Y2hpLCBhZXMoZmlsbCA9IFBXaGl0ZSwgY29sb3VyID0gUFdoaXRlKSkNCmBgYA0KVGhpcyBjZXJ0YWlubHkgYWxsb3dzIHVzIHRvIHNlZSB0aGUgdHJhY3QgZGF0YSBjbGVhcmx5Lg0KDQpJdCBtaWdodCBiZSB1c2VmdWwgdG8gaGF2ZSBzb21lIGJvdW5kYXJpZXMgdG8gaGVscCB1cyBoZXJlLiBDb3VudHkgYm91bmRhcmllcywgZm9yIGluc3RhbmNlIG1pZ2h0IGJlIHVzZWZ1bC4gV2UgY291bGQgZG93bmxvYWQgdGhlIGNvdW50eSBkYXRhLCBvciB3ZSBjb3VsZCBzaW1wbHkgZ2VuZXJhdGUgaXQgZnJvbSB0aGUgdHJhY3QgZGF0YSB3aGljaCB3ZSBhbHJlYWR5IGhhdmUuDQoNCk9uZSBzcGVjaWFsIGZlYXR1cmUgb2Ygc2ltcGxlIGZlYXR1cmVzIChzZikgb2JqZWN0cyBpcyB0aGF0IHdlIGNhbiB1c2UgYGdyb3VwX2J5KClgIGFuZCBgc3VtbWFyaXNlKClgIGFzIHdlIHdvdWxkIG9uIG91ciBkYXRhIHRhYmxlLCBhbmQgaXQgd2lsbCBhbHNvIHJlLWNhbGN1bGF0ZSBhbmQgYWdncmVnYXRlIGdlb21ldHJpZXMgaW4gb3VyIG1hcHMuIEluIHRoaXMgY2FzZSwgd2UgY2FuIHVzZSBvdXIgY2Vuc3VzIHRyYWN0cyAod2hpY2ggYXJlIGhpZXJhcmNoaWNhbCkgdG8gZ2VuZXJhdGUgb3VyIGNvdW50eS1sZXZlbCBkYXRhIGFuZCBnZW9ncmFwaGllcy4gV2hpbGUgd2UncmUgYXQgaXQsIGxldCdzIGFsc28gc3VtbWFyaXplIGNvdW50cyBmb3IgcG9wdWxhdGlvbiwgcmFjZSwgYW5kIGV0aG5pY2l0eToNCmBgYHtyfQ0KY288LWNoaSAlPiUgZ3JvdXBfYnkoQ09VTlRZRlApICU+JSBzdW1tYXJpc2UoDQogIFBvcF9jbyA9IHN1bShQb3ApLA0KICBXaGl0ZV9jbyA9IHN1bShXaGl0ZSksDQogIEJsYWNrX2NvID0gc3VtKEJsYWNrKSwNCiAgQUlBTl9jbyA9IHN1bShBSUFOKSwNCiAgQXNpYW5fY28gPSBzdW0oQXNpYW4pLA0KICBMYXRpbm9fY28gPSBzdW0oTGF0aW5vKSwNCiAgTm9ud2hpdGVfY28gPSBzdW0oTm9ud2hpdGUpDQogICkNCmNvDQpgYGANCg0KTm93IGdvIGFoZWFkIGFuZCBwbG90IHRoZSBjb3VudHktbGV2ZWwgZGF0YSAobm8gZmlsbCB5ZXQpOg0KYGBge3J9DQojIFlvdXIgQ29kZSBIZXJlDQpnZ3Bsb3QoKSArIGdlb21fc2YoZGF0YSA9IGNvKQ0KYGBgDQpXZSBjcmVhdGVkIGNvdW50eSBib3VuZGFyaWVzIGZyb20gb3VyIGNlbnN1cyB0cmFjdHMuDQoNCldlIGNhbiBub3cgbGF5ZXIgdGhlIGNvdW50aWVzIGluIHdpdGggb3VyIHRyYWN0IGxldmVsIGRhdGEuIFdlIG5lZWQgdG8gdGVsbCBnZ3Bsb3Qgbm90IHRvIGluY2x1ZGUgZmlsbCBmb3IgdGhlIGNvdW50eS1sZXZlbCBkYXRhIHNvIHRoYXQgd2UgY2FuIHNlZSB0aGUgdHJhY3RzIGJlbG93IHRoZW06DQoNCmBgYHtyfQ0KZ2dwbG90KCkrDQogIGdlb21fc2YoZGF0YT1jaGksIGFlcyhmaWxsID0gUFdoaXRlLCBjb2xvdXIgPSBQV2hpdGUpKSsNCiAgZ2VvbV9zZihkYXRhPWNvLCBmaWxsPU5BKQ0KYGBgDQpTZWUgaG93IHBsb3R0aW5nIGNvdW50eSBib3VuZGFyaWVzIG92ZXIgdGhlIHRyYWN0LWxldmVsIGRhdGEgaGVscHMgdG8gZ2l2ZSB1cyBhIHBvaW50IG9mIHJlZmVyZW5jZSBmb3Igb3VyIG1hcD8NCg0KV2hpbGUgd2UncmUgYXQgaXQsIGl0IG1pZ2h0IGJlIHVzZWZ1bCBmb3IgdXMgdG8gdGhpbmsgYWJvdXQgb3RoZXIgd2F5cyB0byByZXByZXNlbnQgdGhlc2UgZGF0YS4gVGhlIG1hcCBpcyBoZWxwZnVsLCBidXQgd2UgbWF5IGFsc28gd2FudCB0byBsb29rIGF0IHVuaXZhcmlhdGUgY2hhcmFjdGVyaXN0aWNzLiBCdWlsZGluZyB1cG9uIHlvdXIga25vd2xlZGdlIGZyb20gcHJpb3Igd2Vla3MsIG1ha2UgYSBoaXN0b2dyYW0gb2YgdGhlIHBlcmNlbnRhZ2Ugd2hpdGUgcG9wdWxhdGlvbiBmb3IgdGhlIENoaWNhZ28gTWV0cm8gYXJlYSB1c2luZyBgZ2VvbV9oaXN0b2dyYW0oKWA6DQoNCmBgYHtyfQ0KIyBZb3VyIENvZGUgSGVyZQ0KZ2dwbG90KCkgKyBnZW9tX2hpc3RvZ3JhbShkYXRhPWNoaSwgYWVzKHg9UFdoaXRlKSkNCmBgYA0KVGFrZSBhIGxvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0cmFjdHMgLSBob3cgd291bGQgeW91IGNoYXJhY3Rlcml6ZSBvciBkZXNjcmliZSB0aGlzPw0KDQpXZSBsZWFybmVkIGJyaWVmbHkgYWJvdXQgZmFjZXRpbmcgaW4gb3VyIGludHJvZHVjdG9yeSBkYXRhIHZpc3VhbGl6YXRpb24gbGFiLiBMZXQncyB0cnkgdGhhdCBhZ2FpbiBoZXJlLiBVc2UgZmFjZXRzIHRvIHNwbGl0IG91ciBkYXRhIGludG8gc21hbGxlciBtdWx0aXBsZXMgdGhhdCBjYW4gYmUgcGxvdHRlZCBzZXBhcmF0ZWx5LiBMZXQncyBhZGQgYSBmYWNldCB1c2luZyBgZmFjZXRfd3JhcCgpYCBiYXNlZCB1cG9uIHRoZSBjb3VudHkgKGBmYWNldF93cmFwfkNPVU5UWUZQKWApOg0KDQpgYGB7cn0NCiMgWW91ciBDb2RlIEhlcmUNCmdncGxvdCgpICsgDQpnZW9tX2hpc3RvZ3JhbShkYXRhPWNoaSwgYWVzKHg9UFdoaXRlKSkgKw0KZmFjZXRfd3JhcCh+Q09VTlRZRlApDQoNCmBgYA0KSG93IHdvdWxkIHlvdSBkZXNjcmliZSB0aGlzIHZpc3VhbGl6YXRpb24gaW4gcGxhaW4gdGV4dD8gSG93IG1pZ2h0IHdlIGltcHJvdmUgdGhpcyBvciBtYWtlIGl0IG1vcmUgbGVnaWJsZT8NCkNvdW50eSBgMDMxYCwgcHJlc3VtYWJseSBDb29rLCBoYXMgdGhlIG1vc3QgdHJhY3RzIGJ5IGZhciBhbmQgbW9zdCBjb25zaXN0cyBvZiBob21vZ2Vub3VzbHkgYmxhY2sgYW5kIG1ham9yaXR5IHdoaXRlIHRyYWN0cy4gVGhlIG90aGVyIGNvdW50aWVzIGhhdmUgbXVjaCBmZXdlciB0cmFjdHMsIHdpdGggYSBjbGVhciB3aGl0ZSBtYWpvcml0eSBpbiBtb3N0IG9mIHRoZW0uIEhhdmluZyBtb3JlIGxldmVscyBvbiB0aGUgeSBheGlzLCBhIGJldHRlciBjb2xvciwgYW5kIGF4aXMgbGFiZWxzIChwZXJjZW50YWdlIGFuZCB0cmFjdCBjb3VudCksIGFsb25nIHdpdGggYSBkZXNjcmlwdGl2ZSBjb3VudHkgbmFtZSBmb3IgZWFjaCBjb2RlLCBjb3VsZCBtYWtlIHRoaXMgZWFzaWVyIHRvIHJlYWQgZm9yIGEgbGF5IHBlcnNvbikNCipZb3VyIERlc2NyaXB0aW9uIEhlcmUqDQoNClRyeSB0byBpbXBsZW1lbnQgdGhvc2UgaW1wcm92ZW1lbnRzIHlvdSBtZW50aW9uLg0KYGBge3J9DQojIFlvdXIgQ29kZSBIZXJlDQpnZ3Bsb3QoZGF0YT1jaGksIGFlcyh4PVBXaGl0ZSkpICsgDQpnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICJibGFjayIsZmlsbCA9ICJibHVlIikgKw0Kc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoNSwgMTAsIDE1LCAyMCwgNDAsIDYwLCA4MCwgMTAwKSkrDQpsYWJzKHggPSAiUGVyY2VudGFnZSBXaGl0ZSIsIHkgPSAiTnVtYmVyIG9mIFRyYWN0cyIsDQogICAgIHRpdGxlID0gIlBlcmNlbnRhZ2UgV2hpdGUgUG9wdWxhdGlvbiBpbiBFYWNoIFRyYWN0IGJ5IENvdW50eSIsDQogICAgIHN1YnRpdGxlID0gIkNoaWNhZ28gTWV0cm9wb2xpdGFuIFJlZ2lvbiIsIA0KICAgICBjYXB0aW9uID0gIlNvdXJjZTogVVMgQ2Vuc3VzIEJ1cmVhdSIpICsNCmZhY2V0X3dyYXAofkNPVU5UWUZQKQ0KYGBgDQpOb3cgdGhhdCB5b3UgaGF2ZSBhIGJldHRlciBzZW5zZSBvZiB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB3aGl0ZSBwb3B1bGF0aW9uIHdpdGhpbiB0aGUgcmVnaW9uLCB0cnkgeW91ciBoYW5kIGF0IGluZGVwZW5kZW50bHkgdmlzdWFsaXppbmcgb3RoZXIgcmFjaWFsIGdyb3VwczoNCg0KYGBge3J9DQojIFlvdXIgV29yayBIZXJlDQpnZ3Bsb3QoZGF0YT1jaGksIGFlcyh4PVBCbGFjaykpICsgDQpnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICJibGFjayIsZmlsbCA9ICJvcmFuZ2UiKSArDQpzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYyg1LCAxMCwgMTUsIDIwLCA1MCwgMTAwLCAxNTAsIDIwMCkpKw0KbGFicyh4ID0gIlBlcmNlbnRhZ2UgQmxhY2siLCB5ID0gIk51bWJlciBvZiBUcmFjdHMiLA0KICAgICB0aXRsZSA9ICJQZXJjZW50YWdlIEJsYWNrIFBvcHVsYXRpb24gaW4gRWFjaCBUcmFjdCBieSBDb3VudHkiLA0KICAgICBzdWJ0aXRsZSA9ICJDaGljYWdvIE1ldHJvcG9saXRhbiBSZWdpb24iLCANCiAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IFVTIENlbnN1cyBCdXJlYXUiKSArDQpmYWNldF93cmFwKH5DT1VOVFlGUCkNCg0KZ2dwbG90KGRhdGE9Y2hpLCBhZXMoeD1QTGF0aW5vKSkgKyANCmdlb21faGlzdG9ncmFtKGNvbG9yID0gImJsYWNrIixmaWxsID0gImdyZWVuIikgKw0Kc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoNSwgMTAsIDMwLCA1MCwgNzAsIDEwMCkpKw0KbGFicyh4ID0gIlBlcmNlbnRhZ2UgTGF0aW5vIiwgeSA9ICJOdW1iZXIgb2YgVHJhY3RzIiwNCiAgICAgdGl0bGUgPSAiUGVyY2VudGFnZSBMYXRpbm8gUG9wdWxhdGlvbiBpbiBFYWNoIFRyYWN0IGJ5IENvdW50eSIsDQogICAgIHN1YnRpdGxlID0gIkNoaWNhZ28gTWV0cm9wb2xpdGFuIFJlZ2lvbiIsIA0KICAgICBjYXB0aW9uID0gIlNvdXJjZTogVVMgQ2Vuc3VzIEJ1cmVhdSIpICsNCmZhY2V0X3dyYXAofkNPVU5UWUZQKQ0KYGBgDQoNCiMgTWVhc3VyaW5nIFJhY2lhbCBTZWdyZWdhdGlvbg0KDQpOb3cgdGhhdCB3ZSBoYXZlIGEgYmFzaWMgaWRlYSBvZiB0aGUgcmFjaWFsIGRpc3RyaWJ1dGlvbiBmb3IgY2Vuc3VzIHRyYWN0cyB3aXRoaW4gdGhlIHJlZ2lvbiwgd2UgY2FuIHN0YXJ0IHRvIHRoaW5rIGFib3V0IHN1bW1hcnkgbWVhc3VyZXMgb2YgdGhlIGV4dGVudCB0byB3aGljaCB0aGVzZSBncm91cHMgYXJlIHNlZ3JlZ2F0ZWQgd2l0aGluIHRoZSByZWdpb24uIFdlIHdpbGwgdXNlIGNlbnN1cyB0cmFjdHMgYXMgYSB1bml0IG9mIGFuYWx5c2lzIHRvIGhlbHAgdXMgZGVzY3JpYmUgY291bnR5LWxldmVsIHJhY2lhbCBzZWdyZWdhdGlvbi4NCg0KIyMgRGlzc2ltaWxhcml0eQ0KKkRpc3NpbWlsYXJpdHkqIGlzIGEgY29tbW9uIG1lYXN1cmUgb2YgKmV2ZW5uZXNzKiBiZXR3ZWVuIHR3byBwb3B1bGF0aW9ucyAtIGRpc3NpbWlsYXJpdHkgbWVhc3VyZXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIG1pbm9yaXR5IHBvcHVsYXRpb24gd2l0aGluIGEgbWFqb3JpdHkgcG9wdWxhdGlvbi4gQ29uY2VwdHVhbGx5LCBkaXNzaW1pbGFyaXR5IG1lYXN1cmVzIHRoZSBwcm9wb3J0aW9uIG9mIHRoYXQgbWlub3JpdHkgb3Igc3ViZ3JvdXAgcG9wdWxhdGlvbiB0aGF0IHdvdWxkIG5lZWQgdG8gbW92ZSBpbiBvcmRlciB0byBiZSBlcXVhbGx5IGRpc3RyaWJ1dGVkIHdpdGggdGhlIG1ham9yaXR5IHBvcHVsYXRpb24uIERpc3NpbWlsYXJpdHkgaXMgY2FsY3VsYXRlZCBhcyBmb2xsb3dzOg0KDQokRCA9IC41KlxzdW1faSB8XGZyYWN7Yl9pfXtCfS1cZnJhY3t3X2l9e1d9fCQNCndoZXJlDQokYl9pJCBpcyB0aGUgbnVtYmVyIG9mIGJsYWNrcyBpbiB0cmFjdCAqaSoNCiRCJCBpcyB0aGUgbnVtYmVyIG9mIGJsYWNrcyBmb3IgdGhlIGNvdW50eQ0KJHdfaSQgaXMgdGhlIG51bWJlciBvZiB3aGl0ZXMgaW4gdHJhY3QgKmkqDQokVyQgaXMgdGhlIG51bWJlciBvZiB3aGl0ZXMgZm9yIHRoZSBjb3VudHkNCg0KTm93IHRoYXQgd2Uga25vdyB0aGUgZm9ybXVsYSwgd2UgY2FuIHN0YXJ0IHRoaW5raW5nIGFib3V0IGhvdyB0byB0cmFuc2xhdGUgdGhpcyBpbnRvIGRwbHlyIG5vdGF0aW9uLg0KDQojIyMgQmxhY2stV2hpdGUgRGlzc2ltaWxhcml0eQ0KVGhpcyBsb29rcyBjb21wbGljYXRlZCwgYnV0IHdlIGNhbiBhY3R1YWxseSBkbyB0aGlzIGZhaXJseSBzaW1wbHkgd2l0aCBkcGx5ciBub3RhdGlvbi4gTGV0J3Mgc3RhcnQgb2ZmIGJ5IGNhbGN1bGF0aW5nIEJsYWNrLVdoaXRlIGRpc3NpbWlsYXJpdHkuDQoNCldlIGhhdmUgb3VyIHdoaXRlIGFuZCBibGFjayB0cmFjdCBwb3B1bGF0aW9uIGRhdGEgYWxyZWFkeSBpbiBvdXIgaWxfdHJ0IGRhdGEsIGFuZCB3ZSBoYXZlIG91ciBjb3VudHkgZGF0YSBpbiBhIHNlcGFyYXRlIG9iamVjdC4gTGV0J3MgZ28gYWhlYWQgYW5kIGpvaW4gdGhhdCBjb3VudHkgZGF0YSB0byBvdXIgdHJhY3QgZGF0YS4NCg0KYGBge3J9DQpjaGk8LWxlZnRfam9pbihjaGksIGNvICU+JSBzdF9zZXRfZ2VvbWV0cnkoTlVMTCksIGJ5PSJDT1VOVFlGUCIpDQpgYGANCg0KTm90aWNlIHRoYXQgdGhpcyBqb2luIGxvb2tzIHByZXR0eSBzdGFuZGFyZCB3aXRoIHRoZSBleGNlcHRpb24gb2YgYHN0X3NldF9nZW9tZXRyeShOVUxMKWAuIFRoZSBjb3VudHkgbGV2ZWwgZGF0YSBoYXMgc3BhdGlhbCBnZW9tZXRyeSBhc3NvY2lhdGVkIHdpdGggaXQgdGhhdCB3ZSBkbyBub3QgbmVjZXNzYXJpbHkgd2FudCB0byBqb2luIHRvIG91ciB0cmFjdC1sZXZlbCBkYXRhIHNpbmNlIHRoYXQgaGFzIGl0cyBvd24gZ2VvbWV0cnkgYXMgd2VsbC4gYHN0X3NldF9nZW9tZXRyeShOVUxMKWAgcmVtb3ZlcyB0aGUgZ2VvbWV0cnkgZnJvbSB0aGUgY291bnR5IGRhdGEsIGJhc2ljYWxseSB0dXJuaW5nIGl0IGludG8gYSBwbGFpbiBvbGQgZGF0YSB0YWJsZS4NCg0KTm93IHRoYXQgd2UndmUgam9pbmVkIHRoYXQsIHdlIGNhbiBzdGFydCBicmVha2luZyBkb3duIHRoZSBkaXNzaW1pbGFyaXR5IGZvcm11bGEgaW50byBjb2RlLWFibGUgcGllY2VzLiBJbnNpZGUgdGhlIGFic29sdXRlIHZhbHVlIHdlIGFyZSBjYWxjdWxhdGluZyBmcmFjdGlvbnMgb2YgdHJhY3QgbWlub3JpdHkgYW5kIG1ham9yaXR5IHBvcHVsYXRpb25zIGNvbXBhcmVkIHRvIHRoZWlyIGNvdW50eS4gV2UgdGhlbiBzdWJ0cmFjdCB0aGVzZSBmcm9tIGVhY2ggb3RoZXIgYW5kIHVzZSBgYWJzKClgIHRvIGZpbmQgdGhlIGFic29sdXRlIHZhbHVlLiBBZnRlciB0aGF0LCB3ZSBuZWVkIHRvIHN1bSB0aGVzZSBhbGwgdXAgYW5kIG11bHRpcGx5IGJ5IC41LiBXZSBhcmUgY2FsY3VsYXRpbmcgdGhlc2UgYnkgY291bnR5LCBzbyB3ZSBjYW4gdXNlIGdyb3VwX2J5KCkgdG8gc3VtIHVwIG9ubHkgdGhlIGRhdGEgZm9yIGVhY2ggY291bnR5IHRvIHByb2R1Y2UgYSBzZXJpZXMgb2YgZmluYWwgZGlzc2ltaWxhcml0eSBzdGF0aXN0aWNzIGZvciBlYWNoIGNvdW50eSBpbiB0aGUgQ2hpY2FnbyBtZXRyb3BvbGl0YW4gYXJlYS4NCg0KYGBge3J9DQpjaGkgJT4lIG11dGF0ZShkaXNzaW1fd2IgPSBhYnMoQmxhY2sgLyBCbGFja19jbyAtIFdoaXRlIC8gV2hpdGVfY28pKSAlPiUgZ3JvdXBfYnkoQ09VTlRZRlApICU+JSBzdW1tYXJpc2UoZGlzc2ltaWxhcml0eSA9IC41KnN1bShkaXNzaW1fd2IpKQ0KYGBgDQoNCkhvdyB3b3VsZCB5b3UgaW50ZXJwcmV0IHRoZXNlIGJsYWNrLXdoaXRlIGRpc3NpbWlsYXJpdHkgdmFsdWVzPyBXaGVyZSBpcyBCbGFjay1XaGl0ZSBkaXNzaW1pbGFyaXR5IHRoZSBoaWdoZXN0IHdpdGhpbiB0aGUgcmVnaW9uPyBXaGVyZSBpcyBpdCB0aGUgbG93ZXN0Pw0KDQpZb3VyIHR1cm4gLSBjYWxjdWxhdGUgbm9ud2hpdGUtd2hpdGUgZGlzc2ltaWxhcml0eSBhbmQgTGF0aW5vLXdoaXRlIGRpc3NpbWlsYXJpdHkgbWVhc3VyZXMgZm9yIHRoZSBjb3VudGllcyBpbiB0aGUgQ2hpY2FnbyBtZXRyb3BvbGl0YW4gYXJlYS4NCg0KIyMgTm9ud2hpdGUtV2hpdGUgRGlzc2ltaWxhcml0eQ0KYGBge3J9DQojIFlvdXIgQ29kZSBIZXJlDQogY2hpICU+JSBtdXRhdGUoZGlzc2ltX3dudyA9IGFicyhOb253aGl0ZSAvTm9ud2hpdGVfY28gLSBXaGl0ZSAvIFdoaXRlX2NvKSkgJT4lIGdyb3VwX2J5KENPVU5UWUZQKSAlPiUgc3VtbWFyaXNlKGRpc3NpbWlsYXJpdHkgPSAuNSpzdW0oZGlzc2ltX3dudykpDQoNCg0KYGBgDQoNCkNvbXBhcmUgYW5kIGNvbnRyYXN0IHRoaXMgd2l0aCBCbGFjay1XaGl0ZSBkaXNzaW1pbGFyaXR5LCBhbmQgd3JpdGUgZG93biB5b3VyIHRob3VnaHRzLg0KDQoqKllvdXIgVGhvdWdodHMgSGVyZSoqDQpDb3VudGllcyBhcmUgbW9zdGx5IGxlc3MgZGlzc2ltaWxhciBpbiB0aGUgbm9ud2hpdGUtd2hpdGUgY2F0ZWdvcnkgdGhhbiB0aGUgYmxhY2std2hpdGUgY2F0ZWdvcnkuDQojIyBMYXRpbm8tV2hpdGUgRGlzc2ltaWxhcml0eQ0KYGBge3J9DQojIFlvdXIgQ29kZSBIZXJlDQogY2hpICU+JSBtdXRhdGUoZGlzc2ltX2x3ID0gYWJzKExhdGlubyAvTGF0aW5vX2NvIC0gV2hpdGUgLyBXaGl0ZV9jbykpICU+JSBncm91cF9ieShDT1VOVFlGUCkgJT4lIHN1bW1hcmlzZShkaXNzaW1pbGFyaXR5ID0gLjUqc3VtKGRpc3NpbV9sdykpDQpgYGANCg0KQ29tcGFyZSBhbmQgY29udHJhc3QgdGhpcyB3aXRoIEJsYWNrLVdoaXRlIGRpc3NpbWlsYXJpdHksIGFuZCB3cml0ZSBkb3duIHlvdXIgdGhvdWdodHMuDQoNCioqWW91ciBUaG91Z2h0cyBIZXJlKioNClRoaXMgaXMgYWxzbyBsZXNzIGRpc3NpbWlsYXIgdGhhbiB0aGUgQmxhY2stV2hpdGUgc2VjdGlvbi4NCg0KIyBJbnRlcmFjdGlvbg0KQSBzZWNvbmQgY29tbW9uIG1lYXN1cmUgb2Ygc2VncmVnYXRpb24gaXMgKmludGVyYWN0aW9uKiB3aGljaCBpcyBhIG1lYXN1cmUgb2YgKmV4cG9zdXJlKi4gSW50ZXJhY3Rpb24gbWVhc3VyZXMgdGhlIGxpa2VsaWhvb2Qgb2YgcG9wdWxhdGlvbiBzdWJncm91cHMgaW50ZXJhY3Rpbmcgd2l0aCBvbmUgYW5vdGhlciBiYXNlZCB1cG9uIHRoZWlyIGRpc3RyaWJ1dGlvbiB3aXRoaW4gYXJlYWwgc3ViIHVuaXRzICh0cmFjdHMpLiBGb3IgaW5zdGFuY2UsIEJsYWNrLVdoaXRlIGludGVyYWN0aW9uIGlzIGNhbGN1bGF0ZWQgYXMgZm9sbG93czoNCg0KJEludGVyYWN0aW9uID0gXHN1bV9pXGZyYWN7Yl9pfXtCfSpcZnJhY3t3X2l9e3RfaX0kDQpXaGVyZQ0KJGJfaSQgaXMgdGhlIEJsYWNrIHBvcHVsYXRpb24gb2YgdHJhY3QgKmkqDQokQiQgaXMgdGhlIEJsYWNrIHBvcHVsYXRpb24gb2YgdGhlIGNvdW50eQ0KJHdfaSQgaXMgdGhlIFdoaXRlIHBvcHVsYXRpb24gb2YgdHJhY3QgKmkqDQokdF9pJCBpcyB0aGUgdG90YWwgcG9wdWxhdGlvbiBvZiB0cmFjdCAqaSoNCg0KR2l2ZW4gdGhhdCB0aGVyZSBhcmUgc29tZSBzaW1pbGFyaXRpZXMgdG8gdGhlIGRpc3NpbWlsYXJpdHkgaW5kZXgsIG1vZGlmeSB5b3VyIGV4aXN0aW5nIGNvZGUgdG8gbWVhc3VyZSBCbGFjayBXaGl0ZSBpbnRlcmFjdGlvbiBmb3IgY291bnRpZXMgaW4gdGhlIENoaWNhZ28gTWV0cm9wb2xpdGFuIEFyZWE6DQpgYGB7cn0NCiMgWW91ciBDb2RlIEhlcmUNCmNoaSAlPiUgbXV0YXRlKGludGVyX3diID0gYWJzKChCbGFjayAvIEJsYWNrX2NvKSAqIChXaGl0ZSAvIFBvcCkpKSAlPiUgZ3JvdXBfYnkoQ09VTlRZRlApICU+JSBzdW1tYXJpc2UoaW50ZXJhY3Rpb24gPSBzdW0oaW50ZXJfd2IsIG5hLnJtID0gVFJVRSkpDQpgYGANClRoZSBvdXRwdXQgaGVyZSBpcyBhY3R1YWxseSBhICpwcm9iYWJpbGl0eSogdGhhdCByYW5nZXMgZnJvbSAwIHRvIDEuIEEgdmFsdWUgY2xvc2VyIHRvIDEgaW5kaWNhdGVzIGEgaGlnaGVyIHByb2JhYmlsaXR5IG9mIHRoZXJlIGJlaW5nIGNvbnRhY3QgYmV0d2VlbiB0aGVzZSB0d28gcG9wdWxhdGlvbiBncm91cHMuIEEgdmFsdWUgY2xvc2VyIHRvIDAgaW5kaWNhdGVzIGxvd2VyIHByb2JhYmlsaXRpZXMgb2YgY29udGFjdC4NCg0KUHJvdmlkZSB5b3VyIGludGVycHJldGF0aW9uIG9mIEJsYWNrLVdoaXRlIEludGVyYWN0aW9uIGZvciBDaGljYWdvIG1ldHJvIGNvdW50aWVzLg0KQ29vayBoYXMgdGhlIGxvd2VzdCBwcm9iYWJpbGl0eSBvZiBpbnRlcmFjdGlvbiBieSBmYXIsIHdoaWxlIEdydW5keSBhbmQgTWNIZW5yeSBoYXZlIG11Y2ggaGlnaGVyIHJhdGVzIG9mIGludGVyYWN0aW9uLiBUaGVzZSB0d28gYXJlIGJvdGggb3ZlciA5MCUgd2hpdGUsIGl0IGlzIHdvcnRoIG1lbnRpb25pbmcuDQpOb3cgZ28gYWhlYWQgYW5kIGNhbGN1bGF0ZSBOb24tV2hpdGUgLSBXaGl0ZSBJbnRlcmFjdGlvbi4NCmBgYHtyfQ0KIyBZb3VyIENvZGUgSGVyZQ0KY2hpICU+JSBtdXRhdGUoaW50ZXJfd253ID0gYWJzKChOb253aGl0ZSAvIE5vbndoaXRlX2NvKSAqIChXaGl0ZSAvIFBvcCkpKSAlPiUgZ3JvdXBfYnkoQ09VTlRZRlApICU+JSBzdW1tYXJpc2UoaW50ZXJhY3Rpb24gPSBzdW0oaW50ZXJfd253LCBuYS5ybSA9IFRSVUUpKQ0KYGBgDQoNCkZpbmFsbHksIGdvIGFoZWFkIGFuZCBjYWxjdWxhdGUgTGF0aW5vIC0gV2hpdGUgSW50ZXJhY3Rpb24uDQpgYGB7cn0NCiMgWW91ciBDb2RlIEhlcmUNCmNoaSAlPiUgbXV0YXRlKGludGVyX3dsID0gYWJzKChMYXRpbm8gLyBMYXRpbm9fY28pICogKFdoaXRlIC8gUG9wKSkpICU+JSBncm91cF9ieShDT1VOVFlGUCkgJT4lIHN1bW1hcmlzZShpbnRlcmFjdGlvbiA9IHN1bShpbnRlcl93bCwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQpIb3cgd291bGQgeW91IGludGVycHJldCBCbGFjay1XaGl0ZSwgTm9uLVdoaXRlIFdoaXRlLCBhbmQgTGF0aW5vLVdoaXRlIGludGVyYWN0aW9uIGpvaW50bHk/IEFjcm9zcyB0aGUgYm9hcmQsIHRoZSBMYXRpbm8tV2hpdGUgaW50ZXJhY3Rpb25zIGFyZSBtb3N0IHByb2JhYmxlLg0KDQojIElzb2xhdGlvbg0KVGhlIGZpbmFsIG1lYXN1cmUgb2YgcmFjaWFsIHNlZ3JlZ2F0aW9uIHdlJ2xsIGxvb2sgYXQgaW4gdGhpcyBsYWIgaXMgKmlzb2xhdGlvbiogd2hpY2ggaXMgb25seSBtZWFzdXJlZCBmb3Igb25lIGdyb3VwIGF0IGEgdGltZS4gSXNvbGF0aW9uIG1lYXN1cmVzIHRoZSBsaWtlbGlob29kIG9mIGNvbnRhY3QgZm9yIGEgc3ViZ3JvdXAgd2l0aCBvdGhlciBzdWJncm91cCBtZW1iZXJzLiBJdCBpcyBpbnRlcnByZXRlZCBzaW1pbGFybHkgdG8gSW50ZXJhY3Rpb24gKGFzIGEgcHJvYmFiaWxpdHkgcmFuZ2luZyBmcm9tIDAgdG8gMSk6DQoNCklzb2xhdGlvbiBmb3IgQmxhY2tzDQokSXNvbGF0aW9uID0gXHN1bV9pXGZyYWN7Yl9pfXtCfSpcZnJhY3tiX2l9e3RfaX0kDQpXaGVyZQ0KJGJfaSQgaXMgdGhlIEJsYWNrIHBvcHVsYXRpb24gb2YgdHJhY3QgKmkqDQokQiQgaXMgdGhlIEJsYWNrIHBvcHVsYXRpb24gb2YgdGhlIGNvdW50eQ0KJHRfaSQgaXMgdGhlIHRvdGFsIHBvcHVsYXRpb24gb2YgdHJhY3QgKmkqDQoNCk1vZGlmeSB5b3VyIGV4aXN0aW5nIGNvZGUgdG8gY2FsY3VsYXRlIEJsYWNrIElzb2xhdGlvbiBieSBjb3VudHkgZm9yIHRoZSBDaGljYWdvIE1ldHJvcG9saXRhbiBBcmVhOg0KYGBge3J9DQojIFlvdXIgQ29kZSBIZXJlDQpjaGkgJT4lIG11dGF0ZShpc29fYiA9IGFicygoQmxhY2sgLyBCbGFja19jbykgKiAoQmxhY2sgLyBQb3ApKSkgJT4lIGdyb3VwX2J5KENPVU5UWUZQKSAlPiUgc3VtbWFyaXNlKGlzb2xhdGlvbiA9IHN1bShpc29fYiwgbmEucm0gPSBUUlVFKSkNCmBgYA0KIFlvdSBrbm93IHdoYXQgY29tZXMgbmV4dC4gQ2FsY3VsYXRlIE5vbndoaXRlIElzb2xhdGlvbiBhbmQgTGF0aW5vIElzb2xhdGlvbiBhbmQgaW50ZXJwcmV0IHdoYXQgeW91IHNlZS4NCg0KTm9ud2hpdGUgSXNvbGF0aW9uDQpgYGB7cn0NCiMgWW91ciBDb2RlIEhlcmUNCmNoaSAlPiUgbXV0YXRlKGlzb19udyA9IGFicygoTm9ud2hpdGUgLyBOb253aGl0ZV9jbykgKiAoTm9ud2hpdGUgLyBQb3ApKSkgJT4lIGdyb3VwX2J5KENPVU5UWUZQKSAlPiUgc3VtbWFyaXNlKGlzb2xhdGlvbiA9IHN1bShpc29fbncsIG5hLnJtID0gVFJVRSkpDQoNCmBgYA0KDQpMYXRpbm8gSXNvbGF0aW9uDQpgYGB7cn0NCiMgWW91ciBDb2RlIEhlcmUNCmNoaSAlPiUgbXV0YXRlKGlzb19sID0gYWJzKChMYXRpbm8gLyBMYXRpbm9fY28pICogKExhdGlubyAvIFBvcCkpKSAlPiUgZ3JvdXBfYnkoQ09VTlRZRlApICU+JSBzdW1tYXJpc2UoaXNvbGF0aW9uID0gc3VtKGlzb19sLCBuYS5ybSA9IFRSVUUpKQ0KDQpgYGANCg0KIyBJbmNvbWUgSW5lcXVhbGl0eQ0KV2hpbGUgd2UncmUgYXQgaXQsIGxldCdzIGFsc28gcGF5IGF0dGVudGlvbiB0byBzZWdyZWdhdGlvbiBvbiB0aGUgYmFzaXMgb2YgaW5jb21lLiBBIHNpbXBsZSBtZWFzdXJlIG9mIGluY29tZSBpbmVxdWFsaXR5IGFuZCBkaXN0cmlidXRpb24gaXMgdG8gY2FsY3VsYXRlIHRoZSBkaWZmZXJlbmNlIGluIG1lZGlhbiBpbmNvbWUgYmV0d2VlbiB0aGUgY291bnR5IGFuZCB0aGUgY2Vuc3VzIHRyYWN0cyB0aGF0IG1ha2UgdXAgdGhlIGNvdW50eS4NCg0KV2UgaGF2ZSBhbGwgb2Ygb3VyIGNlbnN1cyB0cmFjdCBkYXRhLCBidXQgbmVlZCB0byBnbyBiYWNrIHRvIGNlbnN1cyBkYXRhIHRvIGRvd25sb2FkIGNvdW50eSBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBmb3IgZWFjaCBjb3VudHkgaW4gdGhlIENoaWNhZ28gbWV0cm8gYXJlYSAodGhpcyBpcyBub3QgYSBwbGFjZSB0byB0YWtlIHRoZSBhdmVyYWdlIG9yIHdlaWdodGVkIGF2ZXJhZ2Ugb2YgdGhlIHRyYWN0LWxldmVsIGRhdGEpLiBHbyBhaGVhZCBhbmQgZG93bmxvYWQgdGhvc2UgZGF0YSBhbmQgcHJlcGFyZSB0aGVtIGZvciBqb2luaW5nIHRvIG91ciB0cmFjdCBkYXRhOg0KYGBge3J9DQojIFlvdXIgQ29kZSBIZXJlDQpCMTkwMTM8LWdldF9hY3MoZ2VvZ3JhcGh5ID0gImNvdW50eSIsIHN0YXRlID0gc3RhdGUsIHZhcmlhYmxlcyA9IEIxOTAxM19WYXJzLCBzdXJ2ZXkgPSBzdXJ2ZXksIHllYXIgPSBETF9ZZWFyLCBvdXRwdXQgPSAid2lkZSIpDQpCMTkwMTMkTUhISV9jbzwtQjE5MDEzJEIxOTAxM18wMDFFDQpCMTkwMTMkTUhISV9jb1tCMTkwMTMkTUhISV9jbyA9PSAiTmFOIl08LU5BDQpCMTkwMTM8LUIxOTAxMyAlPiUgc2VsZWN0KEdFT0lELCBNSEhJX2NvKQ0KYGBgDQoNCk5vdyBzdGFydCB0aGlua2luZyBhYm91dCBob3cgeW91J2xsIGFjY29tcGxpc2ggdGhpcyBqb2luLiBUaGUgY291bnR5LWxldmVsIGRhdGEgaGF2ZSBhIEdFT0lEIHRoYXQgaW5jbHVkZXMgdGhlIGNvbWJpbmVkIHN0YXRlIGFuZCBjb3VudHkgRklQUyBjb2RlcyAoZS5nLiAiMTcwMzEiKSBtZWFucyBJbGxpbm9pcyAtIENvb2sgQ291bnR5LiBZb3VyIHRyYWN0LWxldmVsIGRhdGEgbGlzdHMgdGhlIFN0YXRlIGFuZCBDb3VudHkgRklQUyBjb2RlcyBzZXBhcmF0ZWx5LCBidXQgbm90IHRvZ2V0aGVyLiBSaWdodCBub3csIHlvdSBkb24ndCBoYXZlIGEgY29tbW9uIGZpZWxkIHRvIGpvaW4gb24uDQoNCkdpdmVuIHRoYXQgd2UgY29udmVuaWVudGx5IGhhdmUgc2VwYXJhdGUgc3RhdGUgKFNUQVRFRlApIGFuZCBjb3VudHkgKENPVU5UWUZQKSBjb2Rlcywgd2UgY2FuIGNvbmNhdGVuYXRlIHRoZXNlIHRvZ2V0aGVyIGludG8gYSBjb2RlIHRoYXQgd2lsbCBtYXRjaCB1cCB0byB0aGUgR0VPSUQgZmllbGQgaW4gb3VyIGNvdW50eSBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBkYXRhOg0KYGBge3J9DQpjaGk8LWNoaSAlPiUgbXV0YXRlKENPVU5UWSA9IHBhc3RlMChTVEFURUZQLCBDT1VOVFlGUCkpDQpgYGANCg0KUmVjYWxsIHRoYXQgYHBhc3RlMCgpYCBwYXN0ZXMgZmllbGRzIHRvZ2V0aGVyIHdpdGggbm8gc3BhY2VzIGJldHdlZW4gdGhlbS4NCg0KT2theSBub3cgeW91J3JlIG9uIHRyYWNrIHRvIGdvIGFoZWFkIGFuZCBqb2luIHRoZSBjb3VudHktbGV2ZWwgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgZGF0YSB0byB5b3VyIHRyYWN0LWxldmVsIGRhdGEuIERvIHNvLCBidXQgcmVtZW1iZXIgdGhhdCB5b3VyIGBieT1gIGZpZWxkIHdpbGwgbG9vayBhIGJpdCBkaWZmZXJlbnQgc2luY2UgdGhlIG1hdGNoaW5nIGZpZWxkcyBoYXZlIGRpZmZlcmVudCBuYW1lcyBpbiB0aGUgdHdvIGRhdGFzZXRzOg0KDQpgYGB7cn0NCiMgWW91ciBXb3JrIEhlcmUNCmNoaSA8LSBsZWZ0X2pvaW4oY2hpLCBCMTkwMTMsIGJ5ID1jKCJDT1VOVFkiID0gIkdFT0lEIikpDQoNCmBgYA0KTm93IHdlIGNhbiBjYWxjdWxhdGUgdGhlIHJhdGlvIG9mIGluY29tZSBmb3Igb3VyIGNlbnN1cyB0cmFjdCB0byB0aGF0IG9mIHRoZSBjb3VudHk6DQoNCmBgYHtyfQ0KY2hpPC1jaGkgJT4lIG11dGF0ZShpbmNfcmF0aW8gPSBNSEhJIC8gTUhISV9jbykNCmBgYA0KTm93IGdvIGFoZWFkIGFuZCBtYXAgb3V0IHRoaXMgaW5jb21lIHJhdGlvIHN0YXRpc3RpYyBmb3IgdGhlIENoaWNhZ28gTWV0cm9wb2xpdGFuIEFyZWE6DQpgYGB7cn0NCiMgWW91ciBDb2RlIEhlcmUNCmdncGxvdCgpKw0KICBnZW9tX3NmKGRhdGEgPSBjaGksIGFlcyhmaWxsPWluY19yYXRpbyksIGNvbG91ciA9IE5BKSArDQogICBsYWJzKHRpdGxlID0gIkluY29tZSBSYXRpbyBmb3IgdGhlIENoaWNhZ28gUmVnaW9uIiwgZmlsbCA9ICJJbmNvbWUgUmF0aW8iKSsNCiAgZ2VvbV9zZihkYXRhPWNvLCBmaWxsPU5BKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCldoYXQgd291bGQgYSByYXRpbyBvZiAxIGluZGljYXRlPyBXaGF0IHdvdWxkIGEgcmF0aW8gb2YgNCBpbmRpY2F0ZT8gV2hlcmUgZG8gd2Ugc2VlIGJpZyBkaWZmZXJlbmNlcz8NCkEgUmF0aW8gb2YgMSBtZWFucyB0aGUgdHJhY3QgaGFzIHRoZSBzYW1lIG1lZGlhbiBpbmNvbWUgYXMgdGhlIGNvdW50eSwgd2hpbGUgYSByYXRpbyBvZiA0IHN1Z2dlc3RzIHRoYXQgdGhlIHRyYWN0IGhhcyBhIG11Y2ggaGlnaGVyIG1lZGlhbiBpbmNvbWUgdGhhbiB0aGUgd2hvbGUuIFVuc3VycHJpc2luZ2x5LCBDb29rIGFsc28gaGFzIHRoZSBoaWdoZXN0IHZpc3VhbCAgdmFyaWFuY2UuDQoNCldoaWxlIHdlJ3JlIGF0IGl0LCBpdCBtaWdodCBiZSBpbnRlcmVzdGluZyB0byBjcmVhdGUgYSBzY2F0dGVyIHBsb3QgdGhhdCBpbGx1c3RyYXRlcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcmFjaWFsIGNvbmNlbnRyYXRpb24gYW5kIGluY29tZS4gR2l2ZSB0aGF0IGEgdHJ5IChwbG90IHRoZSBQZXJjZW50IFdoaXRlIG9uIHRoZSBYIGF4aXMgYW5kIHRoZSBpbmNvbWUgcmF0aW8gb24gdGhlIHkgYXhpcyB1c2luZyBnZW9tX3BvaW50KToNCmBgYHtyfQ0KZ2dwbG90KCkrDQogIGdlb21fcG9pbnQoZGF0YT1jaGksIGFlcyh4PVBXaGl0ZSwgeT1pbmNfcmF0aW8pKSArDQogIGxhYnModGl0bGUgPSAiTXkgQ29vbCBQbG90IiwgeCA9ICJQZXJjZW50IFdoaXRlIiwgeSA9ICJJbmNvbWUgUmF0aW8iKQ0KYGBgDQpIb3cgd291bGQgeW91IGRlc2NyaWJlIHRoaXMgcmVsYXRpb25zaGlwPw0KSXQgaXMgcG9zaXRpdmUtIHRoZSBoaWdoZXIgbWVkaWFuIGluY29tZSBvZiBhIHRyYWN0IGluIHJlc3BlY3QgdG8gdGhlIGNvdW50eSwgdGhlIGxhcmdlciB0aGUgcHJvcG9ydGlvbiBvZiB3aGl0ZSByZXNpZGVudHMgDQoNCk5vdyBzZWUgaWYgeW91IGNhbiBhZGQgYSBsaW5lYXIgbGluZSBvZiBiZXN0IGZpdCB0byB0aGVzZSBkYXRhIHVzaW5nIGdlb21fc21vb3RoICh5b3UnbGwgbmVlZCB0byBzZXQgYG1ldGhvZCA9IGxtYCB0byBnZXQgYSBmaXR0ZWQgbGluZWFyIG1vZGVsKToNCg0KYGBge3J9DQojIFlvdXIgQ29kZSBIZXJlDQpnZ3Bsb3QoKSsNCiAgZ2VvbV9wb2ludChkYXRhPWNoaSwgYWVzKHg9UFdoaXRlLCB5PWluY19yYXRpbykpICsNCiAgZ2VvbV9zbW9vdGgoZGF0YT1jaGksIG1ldGhvZD0gbG0sIGFlcyh4PVBXaGl0ZSwgeT1pbmNfcmF0aW8pKSArDQogIGxhYnModGl0bGUgPSAiTXkgQ29vbCBQbG90IiwgeCA9ICJQZXJjZW50IFdoaXRlIiwgeSA9ICJJbmNvbWUgUmF0aW8iKQ0KYGBgDQpXaGF0J3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBwZXJjZW50IHdoaXRlIHBvcHVsYXRpb24gYW5kIHRoZSBpbmNvbWUgcmF0aW8/DQpQb3NpdGl2ZSwgYXMgb25lIHJpc2VzLCBzbyBkb2VzIHRoZSBvdGhlci4NCg0KV2hhdCB3b3VsZCBpdCBsb29rIGxpa2UgdG8gc3BsaXQgdGhpcyBvdXQgYnkgY291bnRpZXMgdXNpbmcgZmFjZXRzPw0KYGBge3J9DQojIFlvdXIgQ29kZSBIZXJlDQpnZ3Bsb3QoKSsNCiAgZ2VvbV9wb2ludChkYXRhPWNoaSwgYWVzKHg9UFdoaXRlLCB5PWluY19yYXRpbykpICsNCiAgZ2VvbV9zbW9vdGgoZGF0YT1jaGksIG1ldGhvZD0gbG0sIGFlcyh4PVBXaGl0ZSwgeT1pbmNfcmF0aW8pKSArDQogIGxhYnModGl0bGUgPSAiTXkgQ29vbCBQbG90IiwgeCA9ICJQZXJjZW50IFdoaXRlIiwgeSA9ICJJbmNvbWUgUmF0aW8iKSsNCiAgZmFjZXRfd3JhcCh+Q09VTlRZRlApDQpgYGANCkNvbmdyYXR1bGF0aW9ucywgeW91IGhhdmUgbGVhcm5lZCBzb21lIHdheXMgdG8gY2FsY3VsYXRlIGNvbW1vbiBtZWFzdXJlcyBvZiBzZWdyZWdhdGlvbiwgYW5kIGhhdmUgYXBwbGllZCB0aGVzZSBtZWFzdXJlcyBhcyBwYXJ0IG9mIGEgZGF0YSBwaXBlbGluZS4NCg0KQnkgY2hhbmdpbmcgeW91ciBkb3dubG9hZCBjYWxscyBhdCB0aGUgdmVyeSBiZWdpbm5pbmcgb2YgdGhpcyBsYWIgd2hlcmUgeW91IGRvd25sb2FkIGFjcyBkYXRhLCB5b3UgY291bGQgZWFzaWx5IGNyZWF0ZSBzZWdyZWdhdGlvbiBtZWFzdXJlcyBmb3Igb3RoZXIgcGxhY2VzLiBTZWUgd2hhdCB5b3UgbmVlZCB0byBkbyB0byBtb2RpZnkgdGhlIGNvZGUgdG8gcnVuIGZvciBhbm90aGVyIG1ldHJvcG9saXRhbiBhcmVhIG9yIGNvdW50eS4NCg0KIyBFeHRlbmRpbmcgdGhpcyBMYWINCk5vdyB0aGF0IHlvdSBoYXZlIHNvbWUgbmV3IHRvb2xzIHRoYXQgeW91IGFyZSBmYW1pbGlhciB3aXRoLCBzdGFydCBleHBsb3JpbmcgdGhlc2UgZGF0YSBtb3JlLiBNYWtlIG1hcHMgZm9yIG90aGVyIHJhY2lhbCBncm91cHMuIEV4cGxvcmUgZGltZW5zaW9ucyBvZiBzZWdyZWdhdGlvbiBmb3Igb3RoZXIgZ3JvdXBzLg0KDQoxLiBDYW4geW91IHByb2R1Y2UgdGhlIGRhdGEgd2hpY2ggd291bGQgcG9wdWxhdGUgYSBzdW1tYXJ5IHRhYmxlIG9mIG1pbm9yaXR5LW1ham9yaXR5IGRpc3NpbWlsYXJpdHk/IFdoaWNoIGdyb3VwcyBmYWNlIHRoZSBoaWdoZXN0IGxldmVscyBvZiBzZWdyZWdhdGlvbj8NCg0KMi4gSG93IGRvZXMgaW5jb21lIHJlbGF0ZSB0byBsZXZlbHMgb2Ygc2VncmVnYXRpb24/IFRoaW5rIGFib3V0IGhvdyB5b3UgbWlnaHQgdXNlIHRoZSBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBzdGF0aXN0aWMgdG8gZXhwbG9yZSB0aGUgcmVsYXRpb25zaGlwLg0KDQozLiBXaGF0IGFyZSBvdGhlciBmb3JtcyBvZiBzZWdyZWdhdGlvbiB0aGF0IG1pZ2h0IGJlIHVzZWZ1bCB0byBleHBsb3JlIChhc2lkZSBmcm9tIHJhY2lhbCBhbmQgaW5jb21lIHNlZ3JlZ2F0aW9uKT8=